System.Timers.Timer 与 System.Threading.Timer

Posted

技术标签:

【中文标题】System.Timers.Timer 与 System.Threading.Timer【英文标题】:System.Timers.Timer vs System.Threading.Timer 【发布时间】:2010-11-27 20:35:03 【问题描述】:

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

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

哪个最好?

【问题讨论】:

【参考方案1】:

这篇文章提供了相当全面的解释:

“Comparing the Timer Classes in the .NET Framework Class Library” - 也可用as a .chm file

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

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

【讨论】:

我认为这段摘录很有启发性:“与 System.Windows.Forms.Timer 不同,System.Timers.Timer 类默认情况下会在从公共语言运行时 (CLR) 线程池。[...] System.Timers.Timer 类提供了一种简单的方法来处理这种困境——它公开了一个公共 SynchronizingObject 属性。将此属性设置为 Windows 窗体(或Windows 窗体上的控件)将确保 Elapsed 事件处理程序中的代码在实例化 SynchronizingObject 的同一线程上运行。" 根据Threading.Timer 的MSDN article 中的线程安全部分,它是完全线程安全的... System.Threading.TimerSystem.Threading.Thread 和通过池获得的线程一样“具有讽刺意味”而不是线程安全的。仅仅因为这些类不牵你的手并管理lock 关键字本身的使用并不意味着这些类不是线程安全的。你不妨说System.Threading.Thread 不是线程安全的,因为它完全一样。 还有System.Timer.Timer间隔只能是Int32 System.Threading.Timer间隔最大可以是Int64 不幸的是,这个高度误导(充其量)的答案被接受并获得了如此高的投票。答案本身中唯一的重要陈述是完全错误的。 SynchronizingObject 不会使计时器对象本身成为线程安全的。它只是确保在特定线程中调用处理计时器事件的您的代码(如果您适当地设置了该属性)。正如文档中明确指出的那样,计时器对象本身仍然保证是线程安全的。另一方面,System.Threading.Timer 对象 特别记录为线程安全的。【参考方案2】:

在他的《CLR Via C#》一书中,Jeff Ritcher不鼓励使用System.Timers.Timer,这个定时器是从System.ComponentModel.Component派生的,允许它在设计中使用Visual Studio 的表面。因此,它仅在您想要在设计表面上使用计时器时才有用。

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

【讨论】:

它可以用于设计表面 - 这并不意味着它必须这样做,并且不这样做不会产生不利影响。阅读该问题较早答案中的文章,Timers.Timer 似乎比 Threading.Timer 更可取。 好吧,什么更可取取决于上下文,对吧?据我了解,System.Threading.Timer 在来自 ThreadPool 的新工作线程上执行传入的回调。我认为这也是为什么它不一定是线程安全的。有点道理。所以,理论上,你不必担心启动你自己的工作线程的繁琐工作,因为这个计时器会为你做这件事。有点看起来非常有用。 使用System.Threading.Timer 类似于使用线程池或创建自己的线程。 当然这些类不会为你处理同步——那是你的工作!线程池线程、您自己的线程和计时器回调都不会处理锁定——在什么对象上、以什么方式以及在什么情况下您需要锁定需要良好的判断,并且计时器的线程版本为您提供了最大的灵活性和粒度。 -1 这个答案从一开始就是主观的或固执己见的,并且没有提供关于为什么 Jeff Ritcher 首选 System.Threading.Timer 的具体信息【参考方案3】:

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

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

System.Windows.Forms.Timer 改为包装原生 message-only-HWND 并使用 Window Timers 在该 HWND 消息循环中引发事件。

如果您的应用没有 UI,并且您想要尽可能轻量级和通用的 .Net 计时器(因为您很高兴自己搞定线程/调度),那么 System.Threading.Timer 就可以做到最好在框架中。

我不完全清楚System.Threading.Timer 所谓的“非线程安全”问题是什么。也许和这个问题中的问题一样:Thread-safety of System.Timers.Timer vs System.Threading.Timer,或者也许每个人的意思是:

    当您使用计时器时,很容易编写竞态条件。例如。看到这个问题: Timer (System.Threading) thread safety

    计时器通知的重新进入,您的计时器事件可以在您完成处理 first 事件之前触发并回调您 时间。例如。看到这个问题:Thread-safe execution using System.Threading.Timer and Monitor

【讨论】:

确实System.Timers.Timer 在内部使用System.Threading.Timer。见source code。 或在 .NET / .NET Core 中:source.dot.net/#System.ComponentModel.TypeConverter/System/…【参考方案4】:

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

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

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

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

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

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

【讨论】:

【参考方案5】:

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

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

【讨论】:

【参考方案6】:

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

Source

【讨论】:

【参考方案7】:

上面没有提到的一个重要区别可能会让您感到困惑,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);

【讨论】:

我最近用 Timers.Timer 遇到了这个问题,这非常痛苦......有什么想法可以用 Threading.Timer 重写吗? ***.com/questions/41618324/… 源代码中有一个空catch。见System.Timers.Timer source code here 天哪,为什么 MS 程序员不能做同样的事情? 示例没有解释一个如何吞下异常而另一个没有。有人可以填写详细信息吗?【参考方案8】:

来自 Microsoft 的相关信息(请参阅 Remarks on 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 Add-In 建议改用System.Threading.Timer

看起来微软在System.Timers.Timer之前更喜欢System.Threading.Timer

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

【讨论】:

看来是真的:github.com/npgsql/npgsql/issues/471#issuecomment-94104090 @Taegost,它的使用也是有限的——请参阅 MSDN msdn.microsoft.com/en-us/library/… 并阅读有关平台可用性的备注。 @astrowalker - 谢谢你,在我发表评论时,这个答案几乎没有细节。由于它现在有我询问的详细信息,我删除了我的评论。 System.Timers.Timer 现在在 .NET Standard 2.0 和 .NET Core 2.0 及更高版本中受支持。 docs.microsoft.com/en-us/dotnet/api/system.timers.timer(滚动到文章末尾) 这个answer也有System.Windows.Threading.DispatcherTimer。【参考方案9】:

正如其他人提到的MS Docs 的链接,System.Timers.TimerSystem.Threading.Timer 之间的一个主要区别是System.Threading.Timer 执行单个回调方法定义一次System.Timers.Timer 对事件做出反应,因此支持多个订阅者,也可以删除。

如上所述,System.Timers.Timer 在内部使用System.Threading.Timer,例如Enable=false 处理内部计时器,并在 Enable=true / Start() 上重新创建它: https://source.dot.net/#System.ComponentModel.TypeConverter/System/Timers/Timer.cs

【讨论】:

以上是关于System.Timers.Timer 与 System.Threading.Timer的主要内容,如果未能解决你的问题,请参考以下文章

简述System.Windows.Forms.Timer 与System.Timers.Timer用法区别

为啥 System.Timers.Timer 能在 GC 中存活,而 System.Threading.Timer 不能?

System.Timers.Timer 严重不准确

使用System.Timers.Timer类实现程序定时执行

System.Timers.Timer

System.Windows.Forms.TimerSystem.Timers.TimerSystem.Threading.Timer