AutoResetEvent vs ManualResetEvent: Attention!

Julien on avr 7th 2008

J'ai effectué quelques tests de montée en charge il y a quelques jours sur le composant sur lequel je travaille. Malheureusement, je me suis rapidement rendu compte que les performances étaient simplement misérables... Le soft était à peine capable de traiter 60 messages par secondes, ce qui était: 1) mauvais et 2) surprenant! (En résumé, c'est une petite brique logiciel qui fait une sorte de transformation/redirection/cache de messages en temps réel)

J'ai donc passé quelques minutes dans DotTrace afin d'avoir un aperçu de l'exécution. J'ai rapidement trouvé que dans le thread qui observait la queue et envoyait les messages, j'avais utilisé une instance de ManualResetEvent à la place de AutoResetEvent.

Si vous ne les avez jamais utilisé, ces 2 classes permettent d'envoyer des signaux entre 2 threads. De cette façon, le thread qui observe la queue ne consomme pas de ressources bêtement tant que le thread qui remplit la queue n'envoie pas un signal pour prévenir qu'il y a quelque chose à récupérer. Par exemple, le thread 1 attendra que la queue soit remplie de la façon suivante:

  1.  
  2. private AutoResetEvent mySignal = new AutoResetEvent(false);
  3.  
  4. private void MonitorQueue()
  5. {
  6. while(!monitorQueue)
  7. {
  8. mySignal.WaitOne();
  9. GetItemsInTheQueueAndDoStuff();
  10. }
  11. }

Et le thread 2 injectera des données avec:

  1.  
  2. public void EnqueueItem(Item myItem)
  3. {
  4. InsertInQueue(myItem);
  5. mySignal.Set();
  6. }
  7.  

Comme je l'ai dis, mon problème venait du fait que j'avais utilisé par erreur une instance de ManualResetEvent à la place de AutoResetEvent. Ces 2 classes sont quasiment identiques, excepté que lorsque vous utilisez ManualResetEvent, vous devez reseter le signal manuellement avec mySignal.Reset(). Dans mon cas, à la place de bloquer sur mySignal.WaitOne(), le code bouclait en permanence et consommait une quantité de CPU très importante.

J'ai corrigé le problème et relancé mon test de performance: je suis maintenant à 5000 messages par secondes et à moins de 40% de CPU. Bien mieux!

Filed in .NET | No responses yet

Trackback URI | Comments RSS

Leave a reply