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

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

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

哪个最好?

【问题讨论】:

    标签: .net 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.TimerMSDN 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,或者也许每个人的意思是:

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

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

    【讨论】:

    【解决方案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 重写吗? stackoverflow.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 的旧信息不再有效,因此我决定更改答案。

          【讨论】:

          【解决方案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

          【讨论】:

            猜你喜欢
            • 2013-11-03
            • 1970-01-01
            • 2011-06-25
            • 1970-01-01
            • 2016-04-17
            • 1970-01-01
            • 2020-02-15
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多