【问题标题】:C# Timer or Thread.SleepC# 定时器或线程.Sleep
【发布时间】:2019-11-14 20:46:30
【问题描述】:

我正在运行 Windows 服务并使用循环和 Thread.Sleep 重复任务,使用计时器方法会更好吗?

如果是的话,一个代码示例会很棒

我目前正在使用此代码重复

int curMinute;
int lastMinute = DateTime.Now.AddMinutes(-1).Minute;

while (condition)
{
   curMinute = DateTime.Now.Minute;

   if (lastMinute < curMinute) {
         // do your once-per-minute code here
         lastMinute = curMinute;
   }

   Thread.Sleep(50000);      // sleeps for 50 seconds

   if (error condition that would break you out of this) {
       break;      // leaves looping structure
   }
}

【问题讨论】:

    标签: c# timer


    【解决方案1】:

    计时器是一个更好的主意,IMO。这样,如果您的服务被要求停止,它可以非常快速地响应,并且不再调用计时器滴答处理程序......如果您正在睡觉,服务管理器将不得不等待 50 秒或杀死您的线程,两者都不是非常好。

    【讨论】:

    • 为了避免杀死线程,您可以使用 ManualResetEvent.WaitOne(50000) 而不是 Thread.Sleep()。然后,您可以 Set() 等待句柄,以通知线程尽早终止。不过,在这种情况下,计时器可能仍然更可取。
    【解决方案2】:
    class Program
    {
        static void Main(string[] args)
        {
            Timer timer = new Timer(new TimerCallback(TimeCallBack),null,1000,50000);
            Console.Read();
            timer.Dispose();
        }
    
        public static void TimeCallBack(object o)
        {
          curMinute = DateTime.Now.Minute;
          if (lastMinute < curMinute) {
           // do your once-per-minute code here
           lastMinute = curMinute;
        }
    }
    

    代码可能类似于上面的代码

    【讨论】:

    • 请注意,计时器可能会受到额外的系统停顿或睡眠可能不会的高负载的影响。在任何人的实施中都应该考虑到这一点。
    【解决方案3】:

    请务必了解,您的代码将在结束一个循环和开始下一个循环之间休眠 50 秒...

    计时器会每 50 秒调用一次你的循环,这并不完全相同。

    它们都是有效的,但计时器可能是您在这里寻找的。​​p>

    【讨论】:

      【解决方案4】:

      请注意,调用 Sleep() 会冻结服务,因此如果请求停止服务,它不会在 Sleep() 调用期间做出反应。

      【讨论】:

        【解决方案5】:

        是的,使用 Timer 将释放当前大部分时间都在休眠的线程。计时器也会更准确地每分钟触发一次,因此您可能不再需要跟踪 lastMinute

        【讨论】:

          【解决方案6】:

          没有完全回答问题,而是有

          if (error condition that would break you out of this) {
              break;  // leaves looping structure
          }
          

          你应该有

          while(condition && !error_condition)
          

          另外,我会选择Timer

          【讨论】:

            【解决方案7】:

            我已经使用了计时器和 Thread.Sleep(x),或者两者中的任何一个,视情况而定。

            如果我有一小段代码需要重复运行,我可能会使用计时器。

            如果我有一段代码的运行时间可能比延迟计时器要长(例如通过 FTP 从远程服务器检索文件,我无法控制或知道网络延迟或文件大小/计数),我会在周期之间等待一段固定的时间。

            两者都是有效的,但正如前面所指出的,它们做不同的事情。计时器每 x 毫秒运行一次您的代码,即使前一个实例尚未完成。 Thread.Sleep(x) 在完成每次迭代后都会等待一段时间,因此每个循环的总延迟将始终比睡眠时间长(可能不会多)。

            【讨论】:

            • +1 指出,当使用 Timer 时,代码可能同时运行多次。
            • 它可以,除非你使用信号量。
            【解决方案8】:

            我需要一个线程每分钟触发一次 (see question here),我现在根据收到的答案使用了 DispatchTimer

            这些答案提供了一些您可能会觉得有用的参考资料。

            【讨论】:

              【解决方案9】:

              我也同意,使用计时器是最好的选择。我过去曾尝试过与您类似的解决方案,并开始遇到循环失败的问题,我必须等待另一个 Thread.Sleep() 才能再次触发。此外,它确实导致了停止服务的各种问题,我会不断收到关于它没有响应并且必须关闭的错误。

              @Prashanth 的代码应该正是您所需要的。

              【讨论】:

                【解决方案10】:

                您可以使用任何一种。但我认为Sleep() 实现起来简单、清晰且更短。

                【讨论】:

                  【解决方案11】:

                  我不得不说睡眠是一个更好的实现,它背后有一个状态机。这仍然可以让您始终控制应用程序,但允许在任何特定时间需要任何响应。这也将处理比“处理循环中的执行时间”更短的计时器回调

                  例如..

                  <!-- language: c# -->
                  public enum State
                  {
                      Idle = 0,
                      Processing = 1,
                      Stop = 100,
                  }
                  public void Run()
                  {
                      State state = State.Idle;   // could be a member variable, so a service could stop this too
                  
                      double intervalInSeconds = 60;
                      System.DateTime nextExecution = System.DateTime.Now.AddSeconds(intervalInSeconds);
                      while (state != State.Stop)
                      {
                          switch (state)
                          {
                              case State.Idle:
                                  {
                                      if (nextExecution > System.DateTime.Now)
                                      {
                                          state = State.Processing;
                                      }
                                  }
                                  break;
                              case State.Processing:
                                  {
                                      // do your once-per-minute code here
                  
                                      // if you want it to stop, just set it state to stop.
                                      // if this was a service, you could stop execution by setting state to stop, also
                                      // only time it would not stop is if it was waiting for the process to finish, which you can handle in other ways
                  
                                      state = State.Idle;
                                      nextExecution = System.DateTime.Now.AddSeconds(intervalInSeconds);
                                  }
                                  break;
                              default:
                                  break;
                          }
                  
                          System.Threading.Thread.Sleep(1);
                      }
                  }
                  

                  【讨论】:

                  • 你觉得睡觉比使用计时器有什么好处。其他一些人已经给出了你没有解决的睡眠缺点。
                  • 我的角度是始终保持对应用程序的控制,睡眠和/或长计时器将不允许您以小于所选等待时间的间隔处理事物。
                  • 这是一个幼稚的Sleep 实现的问题,您可以改进它。在基于Timer 的解决方案中,这甚至都不是问题;您没有定义等待间隔,而是定义了触发事件的时间间隔,因此根本不需要确定等待多长时间。
                  猜你喜欢
                  • 2020-08-31
                  • 1970-01-01
                  • 1970-01-01
                  • 2013-10-13
                  • 2014-10-28
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多