C#定时器或线程休眠

48

我正在运行一个 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
   }
}
11个回答

43

在我看来,一个计时器是更好的选择。这样,如果您的服务被要求停止,它可以非常快速地响应,并且只需不再调用计时器滴答处理程序... 如果您正在睡觉,则服务管理器将不得不等待 50 秒或终止您的线程,这两种情况都不太友好。


16
为了避免挂起线程,你可以使用ManualResetEvent.WaitOne(50000)代替Thread.Sleep()。然后,你可以设置等待句柄来通知线程尽快终止。在这种情况下,使用计时器可能仍然更可取。 - Thorarin

35
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;
    }
}

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


6
请注意,定时器可能会受到额外的系统延迟或高负载的影响,而这些延迟可能不会出现在休眠中。这应该在任何人的实现中考虑到。 - dyasta

11

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

计时器将每50秒调用您的循环,但并不完全相同。

它们都是有效的,但在这里您可能正在寻找一个计时器。


7

注意,调用Sleep()会冻结服务,因此如果请求停止服务,则在Sleep()调用的持续时间内不会响应。


4

使用计时器可以释放当前大部分时间处于睡眠状态的线程。此外,计时器会更准确地每分钟触发一次,因此您可能不再需要跟踪lastMinute


2
并不完全回答这个问题,而是与其相反,我们可以尝试避免使用 <p> 标签来解决。
if (error condition that would break you out of this) {
    break;  // leaves looping structure
}

您可能需要安装

while(condition && !error_condition)

此外,我建议使用计时器(Timer)

1

我在编程中使用过定时器和Thread.Sleep(x),具体取决于情况。

如果我有一个需要重复运行的短代码片段,我可能会使用定时器。

如果我有一个可能需要比延迟定时器更长时间才能运行的代码片段(例如通过FTP从远程服务器检索文件,其中我无法控制或知道网络延迟或文件大小/数量),我将在循环之间等待固定的时间。

两种方法都是有效的,但正如之前指出的,它们执行不同的操作。定时器每隔x毫秒运行一次您的代码,即使上一个实例尚未完成。Thread.Sleep(x)在每次迭代完成后等待一段时间,因此每个循环的总延迟时间始终会比睡眠期间长(可能不多)。


1
+1 指出了一个问题,当使用计时器时,代码可能会同时运行多次。 - derflocki
除非您使用信号量,否则它可能会发生。 - Casey

1

我需要一个线程每分钟触发一次(在这里查看问题),现在我已经根据我收到的答案使用了基于DispatchTimer的方法。

这些答案提供了一些参考资料,你可能会发现有用。


0

你可以使用任何一个。但我认为Sleep()更容易、清晰且实现更短。


0

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接