System.Timers.Timer与System.Threading.Timer


564

我已经检查出一些可能的计时器最近,和System.Threading.TimerSystem.Timers.Timer是看要紧的,我(因为他们支持线程池)中的那些。

我正在制作游戏,并计划使用所有类型的事件,并以不同的间隔等。

哪个最好?

Answers:


362

本文提供了相当全面的解释:

比较.NET Framework类库中的计时器类 ”-也可以作为.chm文件使用

具体的区别似乎System.Timers.Timer是针对多线程应用程序的,因此通过其SynchronizationObject属性是线程安全的,而System.Threading.Timer具有讽刺意味的是,它不是现成的线程安全的。

我不认为这两者之间存在差异,因为这与您的间隔可以有多小有关。


69
我认为这段摘录很有启发性:“不同于System.Windows.Forms.Timer,默认情况下,System.Timers.Timer类将在从公共语言运行时(CLR)线程池获得的工作线程上调用计时器事件处理程序[...] System.Timers.Timer类提供了一种解决此难题的简便方法,它公开了一个公共SynchronizingObject属性,将该属性设置为Windows窗体的实例(或Windows窗体上的控件)将确保您的Elapsed事件处理程序中的代码在实例化SynchronizingObject的同一线程上运行。”
mico 2010年

7
根据MSDN文章中的Threading.Timer“ 线程安全”部分,它是完全线程安全的...
Pieter 2012年

62
System.Threading.Timer具有讽刺意味的是,它System.Threading.Thread与通过池获得的线程不一样是线程安全的。仅仅因为这些类无法控制您自己并管理lock关键字本身的使用,并不意味着这些类不是线程安全的。您可能会说它System.Threading.Thread不是线程安全的,因为它是完全正确的。
Kirk Woll 2013年

8
而且System.Timer.Timer间隔只能是Int32 System.Threading.Timer间隔可以高达Int64
Brent

11
不幸的是,这个极具误导性的答案(充其量)是被人们接受并受到高度评价的。答案本身唯一的实质性陈述是错误的。该SynchronizingObject不会使计时器对象本身是线程安全的。它只是确保在特定线程中调用了处理计时器事件的代码(如果您适当地设置了该属性)。正如文档中明确指出的那样,timer对象本身仍然不能保证是线程安全的。在另一方面,该System.Threading.Timer对象明确记录为线程安全的。
彼得·杜尼奥

169

System.Threading.Timer是一个普通的计时器。它在线程池线程(从工作池)中调用您。

System.Timers.Timer是一个System.ComponentModel.Component,包装了System.Threading.Timer,并提供了一些用于在特定线程上分派的其他功能。

System.Windows.Forms.Timer而是包装本机消息HWND,并使用窗口计时器在该HWNDs消息循环中引发事件。

如果您的应用程序没有UI,并且您想要的是最轻便,通用的.Net计时器,(因为您很高兴弄清楚自己的线程/派遣),那么System.Threading.Timer它会和框架中的内容一样好。

我还不太清楚所谓的“线程不安全”的问题System.Threading.Timer是什么。也许与这个问题所提出的问题相同:System.Timers.Timer与System.Threading.Timer的线程安全,或者每个人都意味着:

  1. 使用计时器时,很容易编写竞争条件。例如,看到以下问题: Timer(System.Threading)线程安全

  2. 计时器通知,你的计时器事件可以触发并打电话给你回的重入第二处理完之前的时间第一个事件。例如,看到以下问题:使用System.Threading.Timer和Monitor的线程安全执行


正确System.Timers.Timer使用System.Threading.Timer内部。参见源代码
造口术'18

120

Jeff Ritcher在他的书“ CLR via C# ”中不鼓励使用,该计时器派生自,允许将其用于Visual Studio的设计图面。因此,只有在设计图面上要使用计时器时,它才有用。System.Timers.TimerSystem.ComponentModel.Component

他更喜欢System.Threading.Timer在线程池线程上用于后台任务。


36
它可以在设计图面中使用-并不意味着必须这样做,并且不这样做也不会造成不利影响。阅读此问题的早期答案中的文章,Timers.Timer似乎比Threading.Timer更可取。
斯蒂芬·德鲁

6
好吧,更好的选择取决于上下文,对吗?据我了解,System.Threading.Timer在ThreadPool的新工作线程上执行传入的回调。我认为这也是为什么它不一定是线程安全的原因。Kinda很有道理。因此,从理论上讲,您不必担心旋转自己的工作线程的繁琐工作,因为此计时器将为您完成任务。Kinda似乎非常有用。
Finster 2012年

6
使用System.Threading.Timer类似于使用线程池或创建自己的线程。 当然这些类不处理你同步 -这是你的工作!线程池线程,您自己的线程或计时器回调都不会处理锁定-在哪种对象,哪种方式以及在何种情况下需要锁定需要良好的判断力,并且计时器的线程版本为您提供最大的灵活性和灵活性。粒度。
Kirk Woll 2013年

2
-1这个答案从一开始就是主观的或有主见的,并且没有提供有关为什么Jeff Ritcher偏爱System.Threading.Timer的具体信息
Brian Ogden,

42

Microsoft提供的有关此信息(请参阅MSDN上的备注):

  • System.Timers.Timer,它会定期触发一个事件并在一个或多个事件接收器中执行代码。该类旨在在多线程环境中用作基于服务器的组件或服务组件。它没有用户界面,并且在运行时不可见。
  • System.Threading.Timer,它定期在线程池线程上执行一个回调方法。回调方法是在实例化计时器且无法更改时定义的。与System.Timers.Timer类类似,该类旨在用作多线程环境中的基于服务器或服务的组件。它没有用户界面,并且在运行时不可见。
  • System.Windows.Forms.Timer (仅.NET Framework),一个Windows Forms组件,它会定期触发一个事件并在一个或多个事件接收器中执行代码。该组件没有用户界面,并且设计用于单线程环境。它在UI线程上执行。
  • System.Web.UI.Timer (仅.NET Framework),一个ASP.NET组件,该组件定期执行异步或同步网页回发。

有趣的System.Timers.Timer是,.NET Core 1.0弃用了该功能,但在.NET Core 2.0(/。NET Standard 2.0)中再次实现了该功能。.NET Standard 2.0的目标是,从.NET Framework进行切换应该尽可能容易,这可能是它回来的原因。

不建议使用时,建议改用.NET Portability Analyzer Visual Studio加载项System.Threading.Timer

看起来像微软System.Threading.Timer以前所青睐的System.Timers.Timer

编辑说明2018-11-15: 由于有关.NET Core 1.0的旧信息不再有效,因此我想更改答案。



@Taegost,它的使用也受到限制-请参阅MSDNmsdn.microsoft.com/en-us/library/…并阅读有关平台可用性的说明。
astrowalker

@astrowalker-谢谢,在我发表评论时,这个答案几乎没有细节。由于它现在包含我要查询的详细信息,因此删除了我的评论。
Taegost

1
.NET Standard 2.0和.NET Core 2.0及更高版本现在支持System.Timers.Timer。docs.microsoft.com/zh-cn/dotnet/api/system.timers.timer(滚动至文章结尾)
Lee Grissom,


39

上面可能没有提到的一个重要区别是,System.Timers.Timer默默地吞下异常,而System.Threading.Timer事实并非如此。

例如:

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

var timer = new System.Threading.Timer(x =>
{
    var z = 0;
    var i = 1 / z;
}, null, 0, Timeout.Infinite);

1
我最近用Timers.Timer遇到了这个问题,这让我非常痛苦...关于如何使用Threading.Timer重写的任何想法?stackoverflow.com/questions/41618324/...
TEZ温菲尔德

7
源代码中没有空白。看到这里System.Timers.Timer源代码
造口

Omgsh为什么MS程序员实际上不能做同样的事情?
xmedeko

2
示例没有说明一个吞咽异常而另一个不吞咽异常。有人可以填写详细信息吗?
肖恩

24

我从MSDN找到了简短的比较

.NET Framework类库包括四个名为Timer的类,每个类提供不同的功能:

System.Timers.Timer,它会触发一个事件,并定期在一个或多个事件接收器中执行代码。该类旨在在多线程环境中用作基于服务器的组件或服务组件。它没有用户界面,并且在运行时不可见。

System.Threading.Timer,它定期在线程池线程上执行一个回调方法。回调方法是在实例化计时器且无法更改时定义的。与System.Timers.Timer类类似,该类旨在用作多线程环境中的基于服务器或服务的组件。它没有用户界面,并且在运行时不可见。

System.Windows.Forms.Timer,这是一个Windows Forms组件,它会定期触发一个事件并在一个或多个事件接收器中执行代码。该组件没有用户界面,并且设计用于单线程环境。

System.Web.UI.Timer,一个ASP.NET组件,该组件定期执行异步或同步网页回发。


1

这两个类在功能上等效,除了可以通过设置SynchronizingObjectSystem.Timers.Timer通过ISynchronizeInvoke调用其所有计时器到期回调来进行选择。否则,两个计时器都会在线程池线程上调用过期回调。

当将a拖动System.Timers.Timer到Windows Forms设计图面上时,Visual Studio将SynchronizingObject设置为表单对象,这将导致在UI线程上调用所有过期回调。


1

从MSDN:System.Threading.Timer是一个简单,轻便的计时器,它使用回调方法,并由线程池线程提供服务。不建议将其与Windows窗体一起使用,因为其回调不会在用户界面线程上发生。System.Windows.Forms.Timer是与Windows窗体一起使用的更好选择。对于基于服务器的计时器功能,您可以考虑使用System.Timers.Timer,它引发事件并具有其他功能。

资源

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.