Thread.Sleep()的替代品

Sha*_*lle 36 c# multithreading

我们每隔N分钟就要完成一系列任务.所以我们用a创建了一个任务执行器

do { DoWork(); }while(!stopRequested)
Run Code Online (Sandbox Code Playgroud)

现在我们希望在工作周期之间暂停一下.每个人似乎都认为Thread.Sleep()是魔鬼.我已经看到提到使用监视/事件的东西,但我们没有其他人告诉我们做的工作.我们只想每隔N分钟就像发条一样做.

那么有没有替代方案或者我找到了Thread.Sleep的有效使用方法?

另一篇帖子中有人提到WaitHandle.WaitOne()作为替代,但你不能用非静态方法调用它吗?或者至少我不能,因为我得到编译时错误..

非静态字段,方法或属性'System.Threading.WaitHandle.WaitOne(System.TimeSpan)'需要对象引用

Cal*_*her 63

根据我的理解,Thread.Sleep()是坏的,因为它强制线程的资源退出缓存,因此它们必须在之后再次加载.没什么大不了的,但它可能会加剧高负载情况下的性能问题.然后事实是时间不准确,并且它实际上不能等待大约10ms以下的持续时间......

我用这个片段:

new System.Threading.ManualResetEvent(false).WaitOne(1000);
Run Code Online (Sandbox Code Playgroud)

像饼一样简单,它都适合一条线.创建一个永远不会设置的新事件处理程序,然后等待指定为参数的完整超时期限WaitOne().

虽然,对于这种特定情况,Timer可能是更合适的方法:

var workTimer = new System.Threading.Timer(
    (x) => DoWork(),
    null,
    1000, // initial wait period
    300000); // subsequent wait period
Run Code Online (Sandbox Code Playgroud)

然后,您将停止计时器,而不是设置取消变量workTimer.Stop().


编辑:

由于人们仍然觉得这很有用,我应该补充一点,.NET 4.5引入了Task.Delay方法,它更简洁,也支持异步:

Task.Delay(2000).Wait(); // Wait 2 seconds with blocking
await Task.Delay(2000); // Wait 2 seconds without blocking
Run Code Online (Sandbox Code Playgroud)

  • 在找到thread.sleep的替代方法时,我发现你的1行代码段对我自己很好.我只想暂停一秒钟或2秒,并且每次都能使用thread.sleep来登录控制台. (2认同)
  • 我注意到`ManualResetEvent`是`IDisposable`,但是你的代码让匿名实例得到了GC'd.在这种情况下是否存在没有明确调用`Dispose`的风险? (2认同)
  • 好问题。从我在反汇编中可以看到,`ManualResetEvent` 使用基本的 `WaitHandle` 功能,其 Dispose 方法只是处理其内部的 `SafeWaitHandle` 实例。`SafeWaitHandle` 的基类 `SafeHandle` 无论如何都会在它的解构器中显式调用它自己的 Dispose 方法,所以我假设当对象被 GC 处理时,任何非托管操作系统句柄都会在那时被清理。但 2016 年最好的选择是只使用 `Task.Delay` 并避免整个问题。:) (2认同)

Jon*_*eet 23

你要叫WaitOne 一个WaitHandle,肯定.这是一个实例方法.否则怎么知道该等什么?

一些你可以做出反应而不是睡觉的东西肯定会更好,所以你可以注意到取消而无需等待分钟.另一种替代方法WaitHandle是使用Monitor.Wait/ Pulse.

但是,如果您正在使用.NET 4,我会查看任务并行库提供的内容......它的级别略高于其他选项,并且通常是经过深思熟虑的库.

对于常规工作任务,您可能希望使用Timer(System.Threading.Timer或者System.Timers.Timer)或甚可能使用Quartz.NET.


Ree*_*sey 7

Thread.Sleep不是魔鬼 - 你可以用它来做这样的场景.它在短时间内不太可靠.

使用WaitHandle是一个不错的选择 - 但是您需要一个等待句柄的特定实例.但是,它不会单独做到这一点.

话虽如此,大多数时候,这样的操作更适合使用Timer.您是否有理由在循环中处理此问题,而不是仅使用Timer启动工作项?

  • 呃,我们会缺乏关于我不使用计时器的原因的想象力:) (2认同)
  • 不,“Thread.Sleep”不是魔鬼。它更像是光不足王子菲尔(http://en.wikipedia.org/wiki/List_of_Dilbert_characters#Phil_the_Prince_of_Insufficient_Light)。但说实话,“Thread.Sleep”的良好用途相对较少。对我来说,这是代码中的一个危险信号。大多数时候,用计时器替换“Sleep”会产生更干净、更健壮的代码。 (2认同)

Rio*_*ams 5

我能想到的三个选项是:

但我相信许多人会提到 - Thread.Sleep()并不是那么糟糕.