Nouvelles Chroniques d'Amethyste

Penser au Sens, pas au Verbe


Poster un commentaire

Patterns pour haute dispo et scalabilité d’une appli web – Partie II

Exploiter l’asynchronisme

Un thread est occupé lorsqu’il exécute du code. Cela ne signifie pas qu’il soit réellement utilisé. Il peut être en attente pour une des raisons suivantes:
  1. Le code effectue des manipulations de données en mémoire, il est en attente qu’une CPU devienne disponible.
    On parle de code lié à la CPU (CPU-bound)
  2. Le code est en attente d’une requête vers un composant situé en dehors de son process, il est alors I/O bound.
Ces situations ne sont pas très favorables car si le thread ne travaille pas, il n’est pas pour autant disponible pour d’autres tâches.
Une meilleure situation serait de le recycler en attendant que la cause du blocage se résolve.
Les techniques d’asynchronismes permettent d’organiser ce recyclage. Toutefois, l’asynchronisme a un coût. De plus, dans la mesure où le nombre de CPU est tout de même très limité sur un serveur, la mise en oeuvre de code asynchrone est surtout pertinente pour du code I/O bound.

Lire la suite

Publicités


Poster un commentaire

Emettre une requête Http en C#

On utilise de plus en plus souvent des interfaces web api dans les applications, il est donc important de connaître quelques techniques pour émettre des requêtes Http.

.Net propose nativement 3 classes pour faire le boulot:

  1. System.Net.HttpWebRequest
  2. System.Net.Http.HttpClient
  3. System.Net.WebClient

Je ne vais pas aborder HttpWebRequest qui est marquée comme obsolète.

Et puis il y a aussi les frameworks, le plus connu étant RestSharp que je vais aussi présenter.

Allons y!

Lire la suite


Poster un commentaire

Task.Run: pas toujours une bonne idée

Examinons ce bout de code:

class Workload
{
   public int Index { get; set; }

   public void Process()
   {
      // on simule une opération qui prend environ 1 seconde
      Thread.Sleep(1000);
   }
}

Une classe appelée Workload expose une méthode Process qui exécute une opération que nous simulons avec Sleep.

Il ne vous échappe pas que l’opération est synchrone et relativement longue. On pourrait donc être tenté de créer une méthode asynchrone de la façon suivante:


public static void ProcessAsync()
{
   Task.Run(() =>
   {
      // on simule une opération qui prend environ 1 seconde
      Thread.Sleep(1000);
   });
}

Effectivement en apparence la méthode paraît asynchrone, l’interface reprend la main tout de suite après son lancement.

Le seul problème est qu’en général ce n’est pas une bonne solution pour différentes raisons.

La première raison est que la méthode reste malgré tout synchrone. On a toujours un thread qui attend quelque part, c’est juste un autre puisé dans le pool de threads. Cela ne change rien au fait que l’on mobilise des ressources (le thread), mais pire on a instancié des objets (Task) que le GC devra bien libérer un jour ou l’autre et cette opération est douloureuse pour les performances de l’application.

Le résultat de cette transformation est que l’application aura perdu de la scalabilité par rapport à la version synchrone puisqu’elle utilise des ressources supplémentaires!

Ce n’est pas tout, on a suffixé avec Async une méthode. Par convention on attend alors une méthode asynchrone, c’est à dire qui se « scalabilise » dans de bonnes conditions. Hors ce n’est pas le cas puisqu’en interne on va extraire un thread du pool et le mobiliser pendant 1 seconde. Les threads sont une ressources limitée, on doit les utiliser avec parcimonie, surtout si on veut écrire une application qui tient la charge.

 

Cela signifie t’il que l’on ne doit jamais faire Task.Run()? Vous vous doutez bien que non. Simplement il faut le faire lorsque c’est pertinent.

Lire la suite


Poster un commentaire

Eviter de marquer async une méthode void

Marquer comme async une méthode void est une pratique courante et presque toujours une mauvaise idée.

Le problème tient en un point:

Si on écrit async void, alors on ne récupère pas de Task

Il devient alors impossible de savoir quand se termine la méthode asynchrone et (peut-être pire) de gérer correctement les éventuels messages d’erreurs. Vous ne pouvez pas non plus gérer l’annulation de la Task, bref vous perdez le contrôle d’une partie de votre code. C’est rarement une bonne nouvelle.

 

Le symptôme typique de cette erreur est que le code fonctionne la plupart du temps. La plupart du temps oui, mais parfois…

 

Je ne pense pas que l’on fasse cette erreur pour le plaisir d’écrire un code qui marche dans 99%, mais pas 100%, mais surtout parce que l’on n’arrive pas à se débrouiller autrement. J’ai moi-même beaucoup bataillé avec ce problème et j’ai donc eu envie de résumer ce que j’ai pu apprendre sur le sujet.

 

Un article très orienté démo dans lequel je vais essayer de présenter quelques situations typiques et une solution possible.

Lire la suite


Poster un commentaire

Les nouveaux chemins vers l’asynchronisme – VII

On continue la série:

  1. https://amethyste16.wordpress.com/2014/10/02/les-nouveaux-chemins-vers-lasynchronisme-i/
  2. https://amethyste16.wordpress.com/2014/10/03/les-nouveaux-chemins-vers-lasynchronisme-ii/
  3. https://amethyste16.wordpress.com/2015/03/10/les-nouveaux-chemins-vers-lasynchronisme-iii/
  4. https://amethyste16.wordpress.com/2015/03/15/les-nouveaux-chemins-vers-lasynchronisme-iv/
  5. https://amethyste16.wordpress.com/2015/03/17/les-nouveaux-chemins-vers-lasynchronisme-v/
  6. https://amethyste16.wordpress.com/2015/03/24/les-nouveaux-chemins-vers-lasynchronisme-vi/

Avec quelque chose d’important: l’annulation d’une Task. Depuis .NET 4.0, Microsoft fournit pour cela un framework centré autour de CancellationTokenSource. Nous allons l’aborder dans le contexte de l’asynchronisme, mais ce modèle est suffisamment général pour être utilisé dans tout autre situation. Au programme:

  • Techniques de bases avec Task
  • Task et son constructeur
  • async/await

 

Lire la suite


Poster un commentaire

Les nouveaux chemins vers l’asynchronisme – VI

Le sixième volets d’une série:

  1. https://amethyste16.wordpress.com/2014/10/02/les-nouveaux-chemins-vers-lasynchronisme-i/
  2. https://amethyste16.wordpress.com/2014/10/03/les-nouveaux-chemins-vers-lasynchronisme-ii/
  3. https://amethyste16.wordpress.com/2015/03/10/les-nouveaux-chemins-vers-lasynchronisme-iii/
  4. https://amethyste16.wordpress.com/2015/03/15/les-nouveaux-chemins-vers-lasynchronisme-iv/
  5. https://amethyste16.wordpress.com/2015/03/17/les-nouveaux-chemins-vers-lasynchronisme-v/

La version .Net 4.5 nous a gratifiée d’un petit bijou: async/await qui va nous permettre d’écrire du code asynchrone avec une syntaxe de code synchrone. Donc un gain considérablement en simplification, mais aussi son lot de petites subtilités. Allons à la découverte de ce nouveau pattern.

Notez tout de même un détail. Async/await ne dispense absolument pas de connaître Task et son écosystème, bien au contraire. Donc si vous tombez sur cet article pour découvrir l’asynchronisme, je vous conseille vivement de lire les précédents.

Lire la suite


Poster un commentaire

Les nouveaux chemins vers l’asynchronisme – V

Continuons la série:

  1. https://amethyste16.wordpress.com/2014/10/02/les-nouveaux-chemins-vers-lasynchronisme-i/
  2. https://amethyste16.wordpress.com/2014/10/03/les-nouveaux-chemins-vers-lasynchronisme-ii/
  3. https://amethyste16.wordpress.com/2015/03/10/les-nouveaux-chemins-vers-lasynchronisme-iii/
  4. https://amethyste16.wordpress.com/2015/03/15/les-nouveaux-chemins-vers-lasynchronisme-iv/

Je ne vais pas encore aborder la question de async/await, mais parler de petits points techniques importants à connaître:

  • TaskStatus
  • Expériences mystérieuses avec Task.Run
  • TaskCompletionSource<TResult>

Lire la suite