ChatGPT解决这个技术问题 Extra ChatGPT

System.Timers.Timer 与 System.Threading.Timer

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

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

哪个是最好的?


W
Wai Ha Lee

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

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.TimerMSDN article 中的线程安全部分,它是完全线程安全的......
System.Threading.TimerSystem.Threading.Thread 和通过池获得的线程一样“具有讽刺意味”而不是线程安全的。仅仅因为这些类不牵你手并管理 lock 关键字本身的使用并不意味着这些类不是线程安全的。您不妨说 System.Threading.Thread 不是线程安全的,因为它完全一样。
另外 System.Timer.Timer 间隔只能是 Int32 System.Threading.Timer 间隔最多可以是 Int64
不幸的是,这个高度误导(充其量)的答案被接受并获得了如此高的投票。答案本身中唯一的重要陈述是完全错误的。 SynchronizingObject 不会使计时器对象本身成为线程安全的。它只是确保在特定线程中调用处理计时器事件的您的代码(如果您适当地设置了该属性)。正如文档中明确指出的那样,计时器对象本身仍然保证是线程安全的。另一方面,System.Threading.Timer 对象 特别记录为线程安全的。
C
Community

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

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

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 re-entancy of timer notifications,在你完成第一个事件处理之前,你的定时器事件可以触发并再次回调你。例如看到这个问题:Thread-safe execution using System.Threading.Timer and Monitor


确实,System.Timers.Timer 在内部使用了 System.Threading.Timer。请参阅source code
N
Nate B.

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

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


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

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 的旧信息不再有效。


@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(滚动到文章末尾)
s
stovroz

上面没有提到的一个重要区别可能会让您感到困惑,那就是 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 重写吗? stackoverflow.com/questions/41618324/…
源代码中有一个空捕获。请参阅System.Timers.Timer source code here
Omgsh 为什么 MS 程序员不能做同样的事情?
示例没有解释一个如何吞下异常而另一个没有。有人可以填写详细信息吗?
d
default

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

.NET Framework 类库包括四个名为 Timer 的类,每个类都提供不同的功能: System.Timers.Timer,它触发一个事件并定期在一个或多个事件接收器中执行代码。该类旨在用作多线程环境中的基于服务器或服务组件;它没有用户界面,在运行时不可见。 System.Threading.Timer,它定期在线程池线程上执行单个回调方法。回调方法是在定时器实例化时定义的,不能更改。与 System.Timers.Timer 类一样,此类旨在用作多线程环境中的基于服务器或服务组件;它没有用户界面,在运行时不可见。 System.Windows.Forms.Timer,一种 Windows 窗体组件,它触发一个事件并定期在一个或多个事件接收器中执行代码。该组件没有用户界面,设计用于单线程环境。 System.Web.UI.Timer,一个定期执行异步或同步网页回发的 ASP.NET 组件。


G
Greg Gum

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

Source


E
Edward Brey

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

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


E
EricBDev

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

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


关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅