计时器与重复后台工作人员

Posted

技术标签:

【中文标题】计时器与重复后台工作人员【英文标题】:Timer vs. repetitive background worker 【发布时间】:2013-10-07 21:24:29 【问题描述】:

我正在开发一个 Windows 窗体应用程序,它在指定的时间间隔后调用 WCF 服务,并根据从服务接收到的数据显示输出。为此,我计划使用计时器,在 500 毫秒后调用该 WCF 服务方法。但是我的一些同事告诉我使用后台工作程序,然后在Work_Completedevent 上重新运行工作程序。我想知道这两者有什么区别?定时器是否也创建一个后台线程?哪一个最适合长时间运行的任务?

【问题讨论】:

什么定时器?有多个。有些使用线程有些不使用。 【参考方案1】:

Timer 在资源消耗方面几乎肯定更合适。 BackgroundWorker 将为该任务创建一个新线程。创建一个新线程是一项相当昂贵的操作。虽然有许多不同的计时器实现,并且它们的实现会有所不同,但它们通常会依赖于定期触发事件的操作系统工具,这比启动新的专用线程要好。

Timer 对象的大部分主要区别在于它们“准备好”时所做的事情。有的创建一个新的线程池线程;有些有一个专用线程,由计时器的所有实例共享以运行处理程序,有些将代码编组到 UI 线程(或其他一些同步上下文),您可能想要后者。如果您使用在您正在使用的特定 UI 框架中提供的计时器,您将看到它的行为。

【讨论】:

【参考方案2】:

From MSDN website:-

BackgroundWorker 在 ThreadPool 上创建一个线程(通过异步 委托调用)。 BCL 计时器使用 ThreadPool 线程 引发事件,或者在某些情况下会引发滴答/经过/等 UI 线程上的事件(在 WinForms 计时器或 Timers.Timer 提供了 ISynchronizeInvoke)。

BackgroundWorker 为后台线程提供了一个最佳的 API UI 环境。它允许方法在后台运行 线程(通过 DoWork 事件)并提供了一种简单的通知方式 UI 线程上的进度和完成(ProgressChanged 和 RunWorkerCCompleted 事件)而不必担心任何 跨线程调用。

WinForms 计时器在 UI 线程上执行,并且可以安全地触摸任何 UI 元素来自其已用事件。但是,您不能保证 以确切的时间间隔执行,这完全取决于正在发生的事情 用户界面线程。让我重复一件重要的事情:没有 使用此选项的后台线程!

Threading.Timer 是一种“丑陋的 API”计时器。 Timers.Timer 简单 将 Threading.Timer 包装成更好的 API 并提供一种方法 在 UI 线程上自动调用 elapsed 事件(通过 SynchronizingObject 属性)。如果设置 SynchronizingObject 属性,没有代码在后台线程上执行,它立即获取 编组到 UI 线程。

一般来说,在 UI 中,BackgroundWorker 更容易处理 与其他选择相比。

【讨论】:

所以这意味着在更深的系统级别,标准计时器只是一个递归函数? @AishwaryaShiva 没有。你为什么这么说? @Servy 正如我刚刚在上面的答案中读到的那样,计时器在 UI 线程上执行,所以据我所知,我认为它应该是一个递归函数。因为它是 UI 线程(UI 类)的一部分,并且在执行时会冻结 UI。我只是问不确定。其实我想知道更深层次的计时器是什么?我看到了 MSDN 的解释,但它们仅用于开发目的。实际上,我想知道这一点是为了我自己的知识和研究。 @AishwaryaShiva 不需要递归将事件调用编组到 UI 线程;它只需要调用同步对象的适当方法将事件处理程序添加到消息队列中。没有什么递归的。【参考方案3】:

根据我的经验,Background Worker 的主要好处是 ProgressChangedRunWorkerCompleted 事件将在实例化工作者的同一线程上执行。因此,如果您在 UI 线程上启动后台工作程序,则 RunWorkerCompleted 事件也会在 UI 线程上触发。这样一来,如果您想在后台工作完成时更新 UI 组件,就不必担心进行非法的跨线程调用。

【讨论】:

您可以使用(多个)Timer 类,它们也会在 UI 线程中打勾;你不需要 BGW 来获得这种行为。 我认为默认情况下在 UI 线程中打勾的唯一一个是 System.Windows.Forms.Timer。这里有一篇比较计时器的好文章:msdn.microsoft.com/en-us/magazine/cc164015.aspx System.Timers.Timer 可以配置为在 UI 线程中触发,您需要考虑特定于每个 UI 范例的所有计时器。有表单定时器,WPF定时器(DispaterTimer)等【参考方案4】:

标准的System.Windows.Forms.Timer 应该没问题。它在 UI 线程上调用其回调,这意味着当您在回调内部进行处理时,它可能会冻结您的 UI 响应。但这只有在您在回调中做大量工作或阻塞线程时才会出现问题。

为避免阻塞线程,只需执行异步 WCF 调用即可。

BackgroundWorker 对您想做的事情毫无意义。您要做的就是在执行某些代码之前等待 500 毫秒,所以只需使用 System.Windows.Forms.Timer

【讨论】:

以上是关于计时器与重复后台工作人员的主要内容,如果未能解决你的问题,请参考以下文章

后台快速计时器

Observable.interval 不在后台状态下工作

在 Swift 4.2 中,后台获取每秒都在工作

如何在Python中运行后台计时器

iPad 语音识别 - 开发人员访问?

iOS:每 2 分钟在后台播放一次短声[关闭]