[英]Thread.Sleep or Thread.Yield
I have a method that uses a background worker to poll a DLL for a status looking something like this:我有一种方法,它使用后台工作人员轮询 DLL 以获取如下所示的状态:
var timeout = DateTime.Now.AddSeconds(3);
while (System.Status != Status.Complete // our status is not complete
&& DateTime.Now < timeout // have not timed out
&& !_Worker.CancellationPending) // backgroundworker has not been canceled
{
//Thread.Yield();
//Thread.SpinWait(1);
//Thread.Sleep(1);
}
When looking at my CPU %, yield()
and spinwait()
cause my app to shoot up to 50% on my PC.查看我的 CPU % 时,
yield()
和spinwait()
会导致我的应用在我的 PC 上运行高达 50%。 With Sleep(1)
my CPU % stays down at 6%.使用
Sleep(1)
,我的 CPU 百分比保持在 6%。 I have been told that that I should choose Thread.Yield()
, however the spikes in CPU % bother me.有人告诉我我应该选择
Thread.Yield()
,但是 CPU 百分比的峰值困扰着我。 What is best practice for something like this?这样的事情的最佳做法是什么?
Thread.Yield will interrupt the current thread to allow other threads to do work. Thread.Yield将中断当前线程以允许其他线程执行工作。 However, if they do not have any work to do, your thread will soon be rescheduled and will continue to poll, thus 100% utilization of 1 core.
但是,如果他们没有任何工作要做,您的线程很快就会重新安排并继续轮询,从而100%利用1个核心。
Causes the calling thread to yield execution to another thread that is ready to run on the current processor.
使调用线程执行到另一个准备在当前处理器上运行的线程。 The operating system selects the thread to yield to.
操作系统选择要生成的线程。
Thread.Sleep will schedule your thread to run again after the sleep time expires, thus much lower CPU utilization. Thread.Sleep将调度您的线程在睡眠时间到期后再次运行,从而大大降低CPU利用率。
Blocks the current thread for the specified number of milliseconds.
阻止当前线程达到指定的毫秒数。
Given the choice between the two, Thread.Sleep
is better suited for your task. 鉴于两者之间的选择,
Thread.Sleep
更适合您的任务。 However, I agree with the comment from @Bryan that a Threading.Timer
makes for a more elegant solution. 但是,我同意@Bryan的评论,即
Threading.Timer
可以提供更优雅的解决方案。
Answering this question for the post message:为帖子回答这个问题:
What is best practice for something like this?
这样的事情的最佳做法是什么?
You seem to have a case for the SpinWait struct , which exists since .NET 4.0 and is different than the much older SpinWait method .您似乎有SpinWait 结构的案例,该结构自 .NET 4.0 起就存在,并且与更旧的SpinWait 方法不同。
Your code can be upgraded to something like this:你的代码可以升级到这样的:
var timeout = DateTime.Now.AddSeconds(3);
var spinWait = new SpinWait();
while (System.Status != Status.Complete
&& DateTime.Now < timeout
&& !_Worker.CancellationPending)
{
spinWait.SpinOnce();
}
The SpinOnce
method will decide whether to call Thread.Sleep
, Thread.Yield
or do a "busy wait" where there is no yield. SpinOnce
方法将决定是调用Thread.Sleep
、 Thread.Yield
还是在没有 yield 的情况下进行“忙等待”。
Specifically about what the post title (ie Thread.Sleep vs Thread.Yield), here are some up-to-date answers:具体关于帖子标题(即Thread.Sleep vs Thread.Yield),这里有一些最新的答案:
SpinWait
in some cases.SpinWait
慢。 On Windows systems, it is (as of this writing) implemented as call to Win32 API SwitchToThread .Thread.Yield()
, except that it allows switching of the CPU core, and this tend to give more time to threads with same or lower priority before resuming.Thread.Yield()
相同,除了它允许切换 CPU 内核,这往往会在恢复之前为具有相同或更低优先级的线程提供更多时间。 In addition to this additional time, the odds of resuming on a different CPU core are much greater, causing things like L1 or L2 cache to be lost, and further decrease performance.Thread.Yield()
.Thread.Yield()
时才应使用它。 On Windows systems, it is (as of this writing) implemented as call to Win32 API SleepEx .Thread.Yield()
and Thread.Sleep(0)
, the Thread.Sleep(1)
is guaranteed to give the CPU away for some time, which may cool things down.Thread.Yield()
和Thread.Sleep(0)
不同, Thread.Sleep(1)
保证在一段时间内放弃 CPU,这可能会使事情降温。 However, the performance cost is huge, and for that reason it should only be used in conjunction with other "spinning" or "yielding" solutions. Additional comment about this:对此的补充评论:
however the spikes in CPU % bother me
但是 CPU 百分比的峰值困扰着我
From your post, that concern might be because the code has a 3-second timeout.从您的帖子来看,这种担忧可能是因为代码有 3 秒超时。 The
SpinWait
should take care of that, but you can't use the SpinWait
struct for some reason, consider using a smaller timeout, in the order of milliseconds. SpinWait
应该解决这个问题,但由于某种原因您不能使用SpinWait
结构,请考虑使用较小的超时,以毫秒为单位。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.