Thread.Sleep() 的替代方法
每 N 分钟我们想要运行一次任务列表。因此,我们创建了一个任务执行器,
do { DoWork(); }while(!stopRequested)
现在我们希望在工作周期之间有一个暂停。每个人似乎都认为 Thread.Sleep() 是魔鬼。我见过提到使用监视器/事件的东西,但我们没有其他人告诉我们去做工作。我们只想像发条一样每 N 分钟做一些事情。
那么是否有替代方案或者我是否找到了 Thread.Sleep 的有效用法?
另一篇文章中的有人提到 WaitHandle.WaitOne() 作为替代方案,但显然您不能从非静态方法调用它?或者至少我不能,因为我收到编译时错误..
需要对象引用 非静态字段、方法或 财产 'System.Threading.WaitHandle.WaitOne(System.TimeSpan)'
Every N minutes we want to run through a list of tasks. So we've created a task executor with a
do { DoWork(); }while(!stopRequested)
Now we want to have a pause between work cycles. Everyone seems to think Thread.Sleep() is the devil. I've seen mention of using Monitor/Event stuff but we don't have someone else telling us to do work. We just want to do stuff every N minutes like clockwork.
So is there an alternative or have I found a valid use of Thread.Sleep?
Someone in another post mentioned WaitHandle.WaitOne() as an alternative but you can't call that from a non-static method apparently? Or at least I can't because I get a compile time error of..
An object reference is required for
the non-static field, method, or
property
'System.Threading.WaitHandle.WaitOne(System.TimeSpan)'
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
您可以使用 System.Timers.Timer 并在其经过处理程序中执行工作。
You could use a System.Timers.Timer and perform the work in its elapse handler.
对于非异步上下文,请使用此超级方法:
true
如果超时成功,false
如果取消或出错,可以使用cancellationToken
实现兼容性或其他目的目的。该方法存在以下问题:
- 手柄数量限制为 64 个。
- 不能在 STA 线程上使用。
- 显然会消耗资源。
注意:如果不使用
cancellationToken
,则省略它,简单,是等待句柄的实现的一部分!完美的实现:
该解决方案基于本主题,并可选地使用取消,抑制
WaitHandle.WaitAll
的所有限制。Please, for non asynchronous context use this supermethod:
true
if timeout is succeeded,false
if cancelled or error, can usecancellationToken
for compatibility or another purposes.This method has issues how:
-There is a 64 handle limit.
-It cannot be used on an STA thread.
-Obviously can consume resource.
NOTE: If you do not use
cancellationToken
, omit it, simple, is part of implementation to wait the handle!A perfect implementation:
this solution is based in this topic and uses a cancellation optionally, suppress all limitations of
WaitHandle.WaitAll
.据我了解, Thread.Sleep() 不好,因为它强制线程的资源脱离缓存,因此之后必须再次加载它们。没什么大不了的,但它可能会加剧高负载情况下的性能问题。还有一个事实是,计时并不精确,而且它实际上无法等待大约 10 毫秒以下的持续时间......
我使用这个片段:
简单如馅饼,一切都适合一行。创建一个永远不会设置的新事件处理程序,然后等待完整的超时时间,您将其指定为
WaitOne()
的参数。不过,对于这种特定场景,计时器可能是更合适的方法:
然后,您可以使用
workTimer.Stop()
停止计时器,而不是设置取消变量。编辑:
由于人们仍然发现这很有用,我应该补充一点,.NET 4.5 引入了 Task.Delay 方法,更加简洁,而且还支持异步:
By my understanding, Thread.Sleep() is bad because it forces the thread's resources out of the cache, so they have to be loaded again afterwards. Not a big deal, but it could aggravate performance issues in high-load situations. And then there's the fact that the timing isn't precise, and that it effectively can't wait for durations under about 10ms...
I use this snippet:
Easy as pie and it all fits on one line. Creates a new event handler that will never be set, and then waits the full timeout period, which you specify as the argument to
WaitOne()
.Although, for this specific scenario, a Timer would probably be a more appropriate approach:
Then, instead of setting a cancel variable, you would stop the timer with
workTimer.Stop()
.Edit:
Since people are still finding this useful, I should add that .NET 4.5 introduces the Task.Delay method, which is even more concise and also supports async:
当然,您必须在
WaitHandle
上调用WaitOne
。这是一个实例方法。否则它怎么知道要等待什么?最好是有一些你可以做出反应的东西,而不是睡觉,这样你就可以注意到取消,而无需无缘无故地等待几分钟。
WaitHandle
的另一种替代方法是使用Monitor.Wait
/Pulse
。但是,如果您使用 .NET 4,我会研究任务并行库必须提供的功能...它的级别比其他选项稍高,并且通常是一个经过深思熟虑的库。
对于常规工作任务,您可能需要考虑使用
Timer
(System.Threading.Timer
或System.Timers.Timer
),或者可能甚至Quartz.NET。You have to call
WaitOne
on aWaitHandle
, certainly. It's an instance method. Otherwise how would it know what to wait for?It's definitely better to have something you can react to instead of sleep, so that you can notice cancellation without waiting minutes for no reason. Another alternative to
WaitHandle
is to useMonitor.Wait
/Pulse
.However, if you're using .NET 4 I'd look into what the Task Parallel Library has to offer... it's at a slightly higher level than the other options, and is generally a well thought out library.
For regular work tasks you might want to look at using a
Timer
(eitherSystem.Threading.Timer
orSystem.Timers.Timer
) or possibly even Quartz.NET.Thread.Sleep
并不是魔鬼 - 您可以将它用于这样的场景。只是在短时间内不太可靠。使用 WaitHandle 是一个不错的选择 - 但您需要等待句柄的特定实例。然而,它不会单独做到这一点。
话虽这么说,大多数时候,像这样的操作更适合使用计时器。
Thread.Sleep
isn't the devil - you could use it for a scenario like this. It's just not very reliable for short durations.Using a WaitHandle is a good option - but you need a specific instance of a wait handle. It won't do this alone, however.
That being said, most of the time, operations like this are better suited towards using a Timer.
我能立即想到的三个选项是:
System.Threading.Timer
(更多...)Monitor.Wait
(更多...)System.Timers.Timer
(更多...),但我相信很多人都会提到 -
Thread.Sleep()
并不是那么糟糕。The three options that I can think of off the top of my head are :
System.Threading.Timer
(More...)Monitor.Wait
(More...)System.Timers.Timer
(More...)but I am sure as many will mention -
Thread.Sleep()
isn't all that bad.您可以使用在需要停止时设置的 ManualResetEvent,然后对其执行 WaitOne。
You could use an ManualResetEvent that you set when it's time to stop, and then do a WaitOne on it.
我将使用一个等待计时器来发出 AutoResetEvent 信号。您的线程应该等待此 WaitHandle 对象。这是一个小型控制台应用程序,展示了这种方法:
I would use a waiting timer which signals an AutoResetEvent. Your thread should wait for this WaitHandle object. Here is a small console app showing this approach:
正如其他回答者所说,计时器可能很适合您。
如果您确实想要自己的线程,我不会在这里使用 Thread.Sleep,因为如果您需要关闭应用程序,则没有好方法告诉它退出睡眠状态。我以前用过类似的东西。
As other answerers have said, Timers may work well for you.
If you do want your own thread, I wouldn't use Thread.Sleep here, if only because if you need to shut down the application, there's no good way to tell it to exit the sleep. I've used something like this before.
我在 WinForms 应用程序中使用了计时器,并在服务器上使用 ScheduledTask 定期启动控制台应用程序。当我希望它弹出它运行的通知和它发现的内容时,就使用了带有计时器的 WinForms(我已将它们设置为最小化到系统托盘)。对于我只想在服务器出现问题时收到通知的情况,我将它们作为控制台应用程序放在服务器上,并作为计划任务运行。这似乎运作得很好。
我想我尝试在现在使用计时器的应用程序中使用睡眠,但不喜欢结果。一方面,使用计时器,我可以非常轻松地调用最小化的应用程序,以便设置或更改前面的设置。如果应用程序处于睡眠状态,您将很难在其睡眠时重新获得访问权限。
I've used both a Timer in a WinForms application and a console app started periodically by a ScheduledTask on a server. The WinForms with a timer has been used in cases when I want it to pop up notifications that it ran and what it found (I've set these to mimize to the systray). For situations where I only want to be notified if something goes wrong on a server, I've put them on the server as console apps and run them as Scheduled Tasks. That seems to work quite well.
I think I tried using Sleep in the apps where I now use Timers, and didn't like the result. For one thing, using a Timer I am able to call up the minimized app very easily in order to set or change settings on the front. If the app is asleep, you have difficulty regaining access while it is slumbering.
如果你的所有线程正在做的事情是这样的:
那么我建议根本不使用线程。首先,没有特别充分的理由来承担大部分时间都在休眠的专用线程的系统开销。其次,如果在线程停止休眠 30 秒后设置 stop_working 标志,则必须等待四分半钟才能唤醒并终止线程。
我建议像其他人一样:使用计时器:
并关闭:
If all your thread is doing is something like:
Then I would suggest not using a thread at all. First, there's no particularly good reason to incur the system overhead of a dedicated thread that spends most of its time sleeping. Secondly, if you set the
stop_working
flag 30 seconds after the thread stops sleeping, you'll have to wait four and a half minutes before the thread wakes up and terminates.I'd suggest as others have: use a timer:
And to shut down: