System.Timers.Timer vs System.Threading.Timer

565

J'ai récemment vérifié certains des temporisateurs possibles System.Threading.Timeret ce System.Timers.Timersont ceux qui me semblent nécessaires (car ils prennent en charge la mise en commun des threads).

Je fais un jeu et je prévois d'utiliser tous les types d'événements, avec différents intervalles, etc.

Quel serait le meilleur?

TheAJ
la source

Réponses:

363

Cet article propose une explication assez complète:

" Comparaison des classes de temporisation dans la bibliothèque de classes .NET Framework " - également disponible sous forme de fichier .chm

La différence spécifique semble être System.Timers.Timerorientée vers les applications multithread et est donc thread-safe via sa SynchronizationObjectpropriété, alors System.Threading.Timerqu'ironiquement, elle n'est pas thread-safe prête à l'emploi.

Je ne crois pas qu'il y ait une différence entre les deux en ce qui concerne la petite taille de vos intervalles.

David Andres
la source
69
Je pense que cet extrait est instructif: "Contrairement à System.Windows.Forms.Timer, la classe System.Timers.Timer appellera par défaut votre gestionnaire d'événements du minuteur sur un thread de travail obtenu à partir du pool de threads CLR (Common Language Runtime). . [...] La classe System.Timers.Timer fournit un moyen simple de résoudre ce dilemme: elle expose une propriété publique SynchronizingObject. La définition de cette propriété sur une instance d'un Windows Form (ou un contrôle sur un Windows Form) assurez-vous que le code de votre gestionnaire d'événements Elapsed s'exécute sur le même thread sur lequel le SynchronizingObject a été instancié. "
mico
7
Selon la section Sécurité des threads dans Threading.Timerl'article MSDN de , il est parfaitement thread-safe ...
Pieter
62
System.Threading.Timerest aussi "ironiquement" pas thread-safe System.Threading.Threadet les threads obtenus à travers le pool. Ce n'est pas parce que ces classes ne tiennent pas la main et ne gèrent pas l'utilisation du lockmot-clé lui-même que ces classes ne sont pas threadsafe. System.Threading.ThreadAutant dire que ce n'est pas threadsafe, car c'est exactement aussi vrai.
Kirk Woll
8
L'intervalle System.Timer.Timer peut également être uniquement Int32 System.Threading.Timer interval peut aller jusqu'à Int64
Brent
11
Il est regrettable que cette réponse hautement trompeuse (au mieux) soit acceptée et si fortement votée. La seule déclaration matérielle dans la réponse elle-même est tout simplement fausse. Le SynchronizingObjectne rend pas l'objet timer lui-même thread-safe. Il s'assure simplement que votre code pour gérer l'événement timer est appelé dans un thread spécifique (si vous définissez cette propriété de manière appropriée). L'objet timer lui-même n'est pas garanti pour être thread-safe, comme cela est clairement indiqué dans la documentation. D'un autre côté, l' System.Threading.Timerobjet est spécifiquement documenté comme étant thread-safe.
Peter Duniho
169

System.Threading.Timerest une minuterie ordinaire. Il vous rappelle sur un thread de pool de threads (à partir du pool de travail).

System.Timers.Timerest un System.ComponentModel.Componentqui encapsule un System.Threading.Timer, et fournit quelques fonctionnalités supplémentaires utilisées pour la répartition sur un thread particulier.

System.Windows.Forms.Timerplace à la place un HWND natif de message uniquement et utilise des minuteries de fenêtre pour déclencher des événements dans cette boucle de message HWND.

Si votre application n'a pas d'interface utilisateur et que vous voulez le minuteur .Net le plus léger et polyvalent possible, (parce que vous êtes heureux de trouver votre propre thread / répartition), alors System.Threading.Timerc'est aussi bien que possible dans le cadre.

Je ne sais pas vraiment quels sont les problèmes supposés «non sûrs pour les threads» System.Threading.Timer. Peut-être est-ce exactement la même que celle posée dans cette question: Thread-safety of System.Timers.Timer vs System.Threading.Timer , ou peut-être que tout le monde signifie simplement que:

  1. il est facile d'écrire les conditions de course lorsque vous utilisez des minuteries. Par exemple, voir cette question: Sécurité du filetage du minuteur (System.Threading)

  2. réentrée des notifications du minuteur, où votre événement du minuteur peut se déclencher et vous rappeler une deuxième fois avant de terminer le traitement du premier événement. Par exemple, voir cette question: Exécution thread-safe en utilisant System.Threading.Timer et Monitor

Tim Lovell-Smith
la source
Vrai l' System.Timers.Timerutilise en System.Threading.Timerinterne. Voir le code source .
stomie
120

Dans son livre " CLR Via C # ", Jeff Ritcher décourage l'utilisation de System.Timers.Timerce temporisateur System.ComponentModel.Component, ce qui lui permet d'être utilisé dans la surface de conception de Visual Studio. Pour que cela ne soit utile que si vous voulez une minuterie sur une surface de conception.

Il préfère utiliser System.Threading.Timerpour les tâches d'arrière-plan sur un thread de pool de threads.

héros
la source
36
Il peut être utilisé dans une surface de conception - cela ne signifie pas qu'il doit l'être, et il n'y a aucun effet néfaste à ne pas le faire. En lisant l'article dans la réponse précédente à cette question, le Timers.Timer semble beaucoup plus préférable à Threading.Timer.
Stephen Drew
6
Eh bien, ce qui est préférable dépend du contexte, non? Si je comprends bien, System.Threading.Timer exécute le rappel transmis sur un nouveau thread de travail de ThreadPool. Ce qui, je suppose, est également la raison pour laquelle ce n'est pas nécessairement thread-safe. Ça a du sens. Donc, en théorie, vous n'auriez pas à vous soucier du grognement de la rotation de votre propre thread de travail, car cette minuterie le fera pour vous. Cela semble ridiculement utile.
Finster
6
L'utilisation System.Threading.Timers'apparente à l'utilisation d'un pool de threads ou à la création de votre propre thread. Bien sûr, ces classes ne gèrent pas la synchronisation pour vous - c'est votre travail! Ni un thread de pool de threads, votre propre thread, ni un rappel de minuterie ne gèrera le verrouillage - sur quel objet et de quelle manière et dans quelles circonstances vous devez verrouiller nécessite un bon jugement et la version de threading de la minuterie vous offre le plus de flexibilité et granularité.
Kirk Woll
2
-1 cette réponse est subjective ou subjective dès le départ et n'offre aucune information concrète sur les raisons pour lesquelles System.Threading.Timer est préféré par Jeff Ritcher
Brian Ogden
42

Informations de Microsoft à ce sujet (voir Remarques sur MSDN ):

  • System.Timers.Timer , qui déclenche un événement et exécute le code dans un ou plusieurs récepteurs d'événements à intervalles réguliers. La classe est destinée à être utilisée en tant que composant serveur ou service dans un environnement multithread; il n'a pas d'interface utilisateur et n'est pas visible au moment de l'exécution.
  • System.Threading.Timer , qui exécute une méthode de rappel unique sur un thread de pool de threads à intervalles réguliers. La méthode de rappel est définie lorsque le temporisateur est instancié et ne peut pas être modifié. Comme la classe System.Timers.Timer, cette classe est destinée à être utilisée en tant que composant de serveur ou de service dans un environnement multithread; il n'a pas d'interface utilisateur et n'est pas visible au moment de l'exécution.
  • System.Windows.Forms.Timer (.NET Framework uniquement), un composant Windows Forms qui déclenche un événement et exécute le code dans un ou plusieurs récepteurs d'événements à intervalles réguliers. Le composant n'a pas d'interface utilisateur et est conçu pour être utilisé dans un environnement à thread unique; il s'exécute sur le thread d'interface utilisateur.
  • System.Web.UI.Timer (.NET Framework uniquement), un composant ASP.NET qui effectue des publications asynchrones ou synchrones de pages Web à intervalles réguliers.

Il est intéressant de mentionner qu'il System.Timers.Timerétait obsolète avec .NET Core 1.0, mais a été implémenté à nouveau dans .NET Core 2.0 (/ .NET Standard 2.0). L'objectif avec .NET Standard 2.0 était qu'il devrait être aussi facile que possible de passer du .NET Framework, ce qui est probablement la raison pour laquelle il est revenu.

Lorsqu'il était obsolète, le complément Visual Studio Analyzer de Portabilité .NET a recommandé d'utiliser à la System.Threading.Timerplace.

On dirait que Microsoft privilégie System.Threading.Timeravant System.Timers.Timer.

EDIT NOTE 2018-11-15: J'ai la main pour changer ma réponse car les anciennes informations sur .NET Core 1.0 n'étaient plus valides.

ice1e0
la source
2
Il semble que ce soit vrai: github.com/npgsql/npgsql/issues/471#issuecomment-94104090
Marco Sulla
@Taegost, son utilisation est également limitée - voir MSDN msdn.microsoft.com/en-us/library/… et lire les remarques sur la disponibilité de la plateforme.
astrowalker
@astrowalker - Merci pour cela, au moment où j'ai fait le commentaire, cette réponse n'avait presque aucun détail. Puisqu'il a maintenant le détail que je demandais, j'ai supprimé mon commentaire.
Taegost
1
System.Timers.Timer est désormais pris en charge dans .NET Standard 2.0 et .NET Core 2.0 et versions ultérieures. docs.microsoft.com/en-us/dotnet/api/system.timers.timer ( faites défiler jusqu'à la fin de l'article)
Lee Grissom
Il y a aussi System.Windows.Threading.DispatcherTimer par cette réponse .
SpeedCoder5
39

Une différence importante non mentionnée ci-dessus qui pourrait vous attraper est celle qui System.Timers.Timeravale silencieusement les exceptions, alors System.Threading.Timerque non.

Par exemple:

var timer = new System.Timers.Timer { AutoReset = false };
timer.Elapsed += (sender, args) =>
{
    var z = 0;
    var i = 1 / z;
};
timer.Start();

contre

var timer = new System.Threading.Timer(x =>
{
    var z = 0;
    var i = 1 / z;
}, null, 0, Timeout.Infinite);
stovroz
la source
1
J'ai récemment rencontré ce problème avec Timers.Timer et cela a été très douloureux ... Des idées sur la façon de réécrire avec Threading.Timer? stackoverflow.com/questions/41618324/…
Tez Wingfield
7
Il y a une capture vide dans le code source. Voir le code source System.Timers.Timer ici
stomy
Omgsh pourquoi les programmeurs MS ne sont pas vraiment capables de faire les mêmes choses?
xmedeko
2
L'exemple n'explique pas comment l'un avale les exceptions et l'autre non. Quelqu'un pourrait-il remplir les détails?
sean
24

J'ai trouvé une courte comparaison de MSDN

La bibliothèque de classes .NET Framework comprend quatre classes nommées Timer, chacune offrant des fonctionnalités différentes:

System.Timers.Timer, qui déclenche un événement et exécute le code dans un ou plusieurs récepteurs d'événements à intervalles réguliers. La classe est destinée à être utilisée en tant que composant serveur ou service dans un environnement multithread; il n'a pas d'interface utilisateur et n'est pas visible au moment de l'exécution.

System.Threading.Timer, qui exécute une méthode de rappel unique sur un thread de pool de threads à intervalles réguliers. La méthode de rappel est définie lorsque le temporisateur est instancié et ne peut pas être modifié. Comme la classe System.Timers.Timer, cette classe est destinée à être utilisée en tant que composant de serveur ou de service dans un environnement multithread; il n'a pas d'interface utilisateur et n'est pas visible au moment de l'exécution.

System.Windows.Forms.Timer, un composant Windows Forms qui déclenche un événement et exécute le code dans un ou plusieurs récepteurs d'événements à intervalles réguliers. Le composant n'a pas d'interface utilisateur et est conçu pour être utilisé dans un environnement à thread unique.

System.Web.UI.Timer, un composant ASP.NET qui effectue des publications asynchrones ou synchrones de pages Web à intervalles réguliers.

Défaut
la source
1

Les deux classes sont fonctionnellement équivalentes, sauf qu'elles System.Timers.Timeront une option pour appeler tous ses rappels d'expiration de temporisateur via ISynchronizeInvoke en définissant SynchronizingObject . Sinon, les deux temporisateurs invoquent des rappels d'expiration sur les threads du pool de threads.

Lorsque vous faites glisser un System.Timers.Timersur une surface de conception Windows Forms, Visual Studio définit SynchronizingObject sur l'objet de formulaire, ce qui provoque tous les rappels d'expiration à être appelés sur le thread d'interface utilisateur.

Edward Brey
la source
1

De MSDN: System.Threading.Timerest un minuteur simple et léger qui utilise des méthodes de rappel et est servi par des threads de pool de threads. Il n'est pas recommandé de l'utiliser avec Windows Forms, car ses rappels ne se produisent pas sur le thread d'interface utilisateur. System.Windows.Forms.Timerest un meilleur choix pour une utilisation avec Windows Forms. Pour la fonctionnalité de minuterie basée sur le serveur, vous pourriez envisager d'utiliser System.Timers.Timer, qui déclenche des événements et possède des fonctionnalités supplémentaires.

La source

Greg Gum
la source