2008-08-28 18 views
26

J'écris une application qui devra utiliser Timer s, mais potentiellement beaucoup d'entre eux. Quelle est la taille de la classe System.Threading.Timer? La documentation dit simplement que c'est "léger", mais n'explique pas plus loin. Est-ce que ces minuteurs sont aspirés dans un seul thread (ou un très petit pool de threads) qui traite tous les rappels pour le compte d'un , ou est-ce que chaque Timer a son propre thread?Quelle est la taille de System.Threading.Timer?

Je suppose qu'une autre façon de reformuler la question est: Comment le System.Threading.Timer est-il implémenté?

Répondre

29

Je dis cela en réponse à beaucoup de questions: N'oubliez pas que le code source (géré) de l'infrastructure est disponible. Vous pouvez utiliser cet outil pour obtenir tout: http://www.codeplex.com/NetMassDownloader

Malheureusement, dans ce cas précis, beaucoup de la mise en œuvre est en code natif, afin de ne pas regarder ce ...

Ils Cependant, utilisez certainement les threads de pool plutôt qu'un thread par timer. La manière standard d'implémenter une grande collection de temporisateurs (comme le noyau le fait en interne, et je suppose que c'est indirectement la fin de votre grande collection de temporisateurs) est de maintenir la liste triée par le temps-jusqu'à- expiration - le système ne doit donc plus jamais se soucier de vérifier le prochain minuteur qui va expirer, pas toute la liste.

En gros, cela donne O (log n) pour démarrer un temporisateur et O (1) pour traiter les temporisateurs.

Edit: Je viens de chercher dans le livre de Jeff Richter. Il dit (de Threading.Timer) qu'il utilise un seul thread pour tous les objets Timer, ce thread sait quand le prochain timer (c'est-à-dire comme ci-dessus) est dû et appelle ThreadPool.QueueUserWorkItem pour les callbacks comme approprié. Cela a pour effet que si vous ne finissez pas d'effectuer un rappel sur une minuterie avant la prochaine, votre rappel sera renvoyé sur un autre thread de pool. Donc, en résumé, je doute que vous voyiez un gros problème avec beaucoup de minuteries, mais vous pourriez souffrir de l'épuisement du pool de threads si un grand nombre d'entre eux tiraient au même minuteur et/ou leurs rappels sont lents.

+0

Une file d'attente prioritaire serait probablement plus efficace qu'une liste triée, à moins que tous les temporisateurs ne soient ajoutés en bloc au début, puis triés, et qu'ils ne soient pas ajoutés plus tard. – RAL

+0

Bien sûr - 'une liste triée par date-jusqu'à-expiration' pourrait certainement être une sorte de file d'attente prioritaire - je ne voulais pas dire 'une liste qui a eu une opération de tri en cours' –

+1

Je viens de passer du temps sur le code dans le sscli. Notez que le .NET ThreadPool a énormément changé depuis la sortie de Rotor, il est donc tout à fait possible que System.Threading.Timer ait également changé énormément. Quoi qu'il en soit, dans le Rotor, les minuteurs sont conservés dans une liste chaînée et déclenchés par un thread de déclenchement de minuterie dédié. Il y a un thread de déclenchement de temporisation pour toute la durée d'exécution (même dans plusieurs domaines d'application). –

7

Je pense que vous pourriez vouloir repenser votre conception (c'est-à-dire, si vous avez le contrôle sur la conception vous-même). Si vous utilisez autant de minuteurs que cela vous préoccupe, il y a clairement un potentiel de consolidation là-bas.

est ici un bon article de MSDN Magazine il y a quelques années qui compare les trois classes de minuterie disponibles, et donne un aperçu de leur mise en œuvre:

http://msdn.microsoft.com/en-us/magazine/cc164015.aspx

0

^^ comme dit DannySmurf: Consolidez-les. Créez un service de minuterie et demandez-le pour les minuteurs. Il aura seulement besoin de garder 1 minuteur actif (pour l'appel suivant) et un historique de toutes les demandes de minuteur et de recalculer cela sur AddTimer()/RemoveTimer().

5

Consolidez-les. Créer un minuteur service et demander cela pour les minuteries. Il suffit de garder 1 minuterie active (pour le prochain appel à cause) ...

Pour que cela soit une amélioration par rapport à seulement créer beaucoup d'objets Threading.Timer, il faut supposer que ce ISN 't exactement ce que Threading.Timer fait déjà en interne.Je serais intéressé de savoir comment vous êtes arrivé à cette conclusion (je n'ai pas démonté les parties natives du cadre, donc vous pourriez bien avoir raison).