System.Timers.Timer与System.Threading.Timer

The*_*eAJ 541 .net timer

我最近一直在查看一些可能的计时器,而Threading.TimerTimers.Timer对我来说是必要的(因为它们支持线程池).

我正在制作游戏,我计划使用不同类型的活动,间隔不同等.

哪个最好?

Dav*_*res 357

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

" 比较.NET Framework类库中的Timer类 " - 也可用作.chm文件

具体差异似乎System.Timers.Timer是面向多线程应用程序,因此通过其SynchronizationObject属性是线程安全的,而System.Threading.Timer具有讽刺意味的是,它不是开箱即用的线程安全的.

我不认为两者之间存在差异,因为它与您的间隔有多小有关.

  • 我认为这段摘录很有启发性:"与System.Windows.Forms.Timer不同,System.Timers.Timer类默认情况下会调用从公共语言运行时(CLR)线程池获取的工作线程上的timer事件处理程序.[...] System.Timers.Timer类提供了一种处理这种困境的简单方法 - 它公开了一个公共SynchronizingObject属性.将此属性设置为Windows窗体的实例(或Windows窗体上的控件)将确保Elapsed事件处理程序中的代码在实例化SynchronizingObject的同一线程上运行." (66认同)
  • `System.Threading.Timer`与`System.Threading.Thread`和通过池获得的线程一样"具有讽刺意味"并非线程安全.仅仅因为这些类没有掌握并且管理`lock`关键字本身的使用并不意味着这些类不是线程安全的.你可能会说`System.Threading.Thread`不是线程安全的,因为它完全一样. (58认同)
  • 另外System.Timer.Timer间隔只能是Int32 System.Threading.Timer间隔可以达到Int64 (8认同)
  • 根据Threading.Timer`的[线程安全部分] [MSDN文章](http://msdn.microsoft.com/en-us/library/system.threading.timer%28v=vs.110%29.aspx ),它完全是线程安全的...... (7认同)
  • @Brent:那不对.该值可以指定为Int64,但是说"间隔可以达到Int64"使得听起来像是可以使用整个Int64值.实际上,最大值仅为UInt32.MaxValue - 1,4294967294.因此它只提供基于Int32的版本提供的最大值的两倍.请参阅此处的NotSupportedException规范:https://msdn.microsoft.com/en-us/library/3yb9at7c%28v=vs.110%29.aspx (3认同)
  • @PeterDuniho 我正要发表同样的评论。`SynchronizingObject` 确实只是为了回到原来的线程上下文。任何人都可以轻松编写一个定时器回调方法来访问共享变量并使其成为线程不安全的。 (3认同)
  • 不幸的是,这个极具误导性的(最好)答案是被接受并被高度评价的。答案本身唯一的实质性陈述是错误的。`SynchronizingObject`不会使计时器对象本身成为线程安全的。只需确保在特定线程中调用_your code_来处理计时器事件即可(如果您适当地设置了该属性)。正如文档中明确指出的那样,timer对象本身仍然保证不是线程安全的。另一方面,`System.Threading.Timer`对象_is_专门记录为线程安全的。 (2认同)

Tim*_*ith 159

System.Threading.Timer是一个简单的计时器.它会回调一个线程池线程(来自工作池).

System.Timers.Timer是一个System.ComponentModel.Component包装a System.Threading.Timer,并提供一些用于在特定线程上调度的附加功能.

System.Windows.Forms.Timer而是包装本机仅消息HWND并使用窗口定时器来引发该HWND消息循环中的事件.

如果您的应用程序没有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`。请参阅[源代码](https://referencesource.microsoft.com/#System/services/timers/system/timers/Timer.cs,133)。 (2认同)

Her*_*ero 118

在他的书" CLR Via C# "中,Jeff Ritcher不鼓励使用System.Timers.Timer,这个计时器源自System.ComponentModel.Component,允许它在Visual Studio的设计表面中使用.因此,只有在设计图面上需要计时器时它才有用.

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

  • 它可以用在设计表面 - 它并不意味着它必须是,并且没有这样做没有不利影响.阅读早期对这个问题的回答中的文章,Timers.Timer似乎比Threading.Timer更可取. (36认同)
  • 那么,什么是可取的取决于背景,对吧?据我所知,System.Threading.Timer在ThreadPool的新工作线程上执行传入的回调.其中,我假设也是为什么它不一定是线程安全的.有点有道理.因此,从理论上讲,您不必担心启动自己的工作线程的麻烦,因为这个计时器会为您完成.有点似乎非常有用. (6认同)
  • 使用`System.Threading.Timer`类似于使用线程池或创建自己的线程.*当然**这些课程不会为你处理同步* - 这是你的工作!线程池线程,您自己的线程和计时器回调都不会处理锁定 - 在什么对象上以及在什么情况下需要锁定需要良好的判断,并且计时器的线程版本为您提供最大的灵活性和粒度. (6认同)
  • -1这个答案从一开始就是主观的或有主见的,并且没有提供有关为什么Jeff Ritcher首选System.Threading.Timer的具体信息。 (2认同)

ice*_*1e0 38

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

  • System.Timers.Timer,它会定期触发事件并在一个或多个事件接收器中执行代码.该类旨在用作多线程环境中的基于服务器或服务组件; 它没有用户界面,在运行时不可见.
  • System.Threading.Timer,它定期在线程池线程上执行单个回调方法.回调方法是在实例化定时器时定义的,无法更改.与System.Timers.Timer类一样,此类旨在用作多线程环境中的基于服务器或服务组件; 它没有用户界面,在运行时不可见.
  • System.Windows.Forms.Timer (仅限.NET Framework),一种Windows窗体组件,用于触发事件并定期在一个或多个事件接收器中执行代码.该组件没有用户界面,专为在单线程环境中使用而设计; 它在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的旧信息不再有效,我提交了更改我的答案.

  • 这似乎是真的:https://github.com/npgsql/npgsql/issues/471#issuecomment-94104090 (2认同)

sto*_*roz 35

上面没有提到的一个可能会让你感到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();
Run Code Online (Sandbox Code Playgroud)

VS

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

  • 源代码中有一个空的catch.请参阅此处的[System.Timers.Timer源代码](https://referencesource.microsoft.com/#System/services/timers/system/timers/Timer.cs,319) (4认同)
  • Example 没有解释一个如何吞下异常而另一个没有。有人可以填写详细信息吗? (4认同)

Def*_*ult 24

我在MSDN上找到了一个简短的比较

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

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

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

System.Windows.Forms.Timer,一个Windows窗体组件,用于触发事件并定期在一个或多个事件接收器中执行代码.该组件没有用户界面,专为在单线程环境中使用而设计.

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