【问题标题】:C#: What if System.Windows.Forms.Timer interval was not enough for doing a job?C#:如果 System.Windows.Forms.Timer 间隔不足以完成工作怎么办?
【发布时间】:2010-06-29 17:39:27
【问题描述】:

首先,对不起我的英文写作不好。

假设我们有一个带有计时器的获胜表单 (C#)。计时器间隔已设置为 60000 milsec。所以它的滴答事件将每 1 分钟触发一次。假设我们编写了一个名为 Timer1_Tick 的处理滴答事件的方法。如果工作需要超过 1 分钟才能完成怎么办?

【问题讨论】:

  • 使用 WinForms 计时器进行如此冗长的阻塞操作并不是一个好主意,因为它基本上会阻塞消息队列和所有相关的东西(尤其是 UI)。
  • 您需要每分钟运行一次作业,还是需要将作业执行间隔 1 分钟? IE。开始之间一分钟,或工作之间一分钟?如果是后者,只需在开始执行作业时禁用计时器,然后再启用它,这将重置计时器。无论如何,我希望你意识到每分钟执行一个工作,如果这个工作花费超过 1 分钟,就会产生问题。此外,在普通的非基于线程的计时器中执行 1 分钟的作业不是一个好主意,您应该考虑使用线程(例如 BackgroundWorker。)
  • @Lucero:你有什么建议?
  • 对于冗长的操作,使用BackgroundWorker控件。

标签: c# winforms timer


【解决方案1】:

你有几个选择,我能想到的有四个:

  1. 放弃当前作业以开始新作业。当然,这个最大的缺点是如果当前作业无法停止。
  2. 等待当前作业完成,然后再开始新作业。如果每个作业都花费一分钟以上,这可能会给您留下一串待处理的作业。
  3. 不要开始新工作。让当前作业完成,然后等待下一个计时器间隔开始新作业。
  4. 增加作业之间的间隔。这只是在拖延问题。

没有正确的答案。您必须找出最适合您的情况的方法。

我会选择 #3 作为我的第一个解决方案。

【讨论】:

    【解决方案2】:

    设置一个标志,允许您检查长时间运行的作业是否已完成,并且仅在作业已完成时才运行该作业。完成长时间运行的工作后不要忘记重置标志:

    // field
    private bool finishedWork = true;
    
    public void Timer1_Tick(Object o, EventArgs e)
    {
       if (finishedWork)
       {
         finishedWork = false;
    
         // do work
    
         finishedWork = true;
       }
    }
    

    另一种选择是简单地禁用操作之间的计时器:

    public void Timer1_Tick(Object o, EventArgs e)
    {
       if (finishedWork)
       {
         Timer1.Enabled = false;
    
         // do work
    
         Timer1.Enabled= true;
       }
    }
    

    【讨论】:

      【解决方案3】:

      因此,在您开始作业时设置一个标志,并在计时器触发时检查该标志。如果设置了标志,则在计时器处理程序中不执行任何操作。记得在作业完成时清除标志。

      您是否正在分离一个工作线程来完成这项工作?

      【讨论】:

        【解决方案4】:

        另一个计时器事件可能会排队,导致 Timer1_Tick 在它返回后几乎立即被再次调用。 (不过,IIRC,计时器滴答声是最低优先级的消息之一,因此它可能会首先处理它在该点之前排队的任何其他消息,除了可能是绘制消息)。

        请注意,如果您的函数运行时间超过 2 分钟,则可能(读取:可能)只有最新的滴答声会在队列中。

        如果您的刻度处理时间比计时器间隔长,您应该考虑提高间隔。无论哪种方式,您都应该在后台线程中完成工作,并确保如果最后一个滴答的任务没有完成,您不会启动另一个线程。否则,您最终可能会遇到成群结队的线程彼此减慢,直到您的程序因自身的重量而崩溃。

        【讨论】:

          【解决方案5】:

          将进程的当前状态存储在字段或属性中,仅当状态不是“正在运行”时才启动进程。

          【讨论】:

            【解决方案6】:

            在 Timer1_Tick 开始时禁用计时器,然后再启用它?

            【讨论】:

              【解决方案7】:

              .Net 中有多种类型的计时器:一种在System.Timers 命名空间中,另一种在System.Windows.Forms 命名空间中,另一种在System.Threading 中。

              System.Windows.Forms.Timer 控件基于 UI 线程和消息循环,这意味着它将对计时器事件进行排队,如果您的处理程序超出间隔,它将在结束后立即调用。

              另外两个定时器是基于线程的,并且非常准确。他们将在时间过去后重新进入您的处理程序。

              【讨论】:

                猜你喜欢
                • 2016-12-19
                • 1970-01-01
                • 2021-12-26
                • 2010-11-15
                • 1970-01-01
                • 1970-01-01
                • 2018-08-12
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多