[英]Thread.Sleep or Thread.Yield
我有一种方法,它使用后台工作人员轮询 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);
}
查看我的 CPU % 时, yield()
和spinwait()
会导致我的应用在我的 PC 上运行高达 50%。 使用Sleep(1)
,我的 CPU 百分比保持在 6%。 有人告诉我我应该选择Thread.Yield()
,但是 CPU 百分比的峰值困扰着我。 这样的事情的最佳做法是什么?
Thread.Yield将中断当前线程以允许其他线程执行工作。 但是,如果他们没有任何工作要做,您的线程很快就会重新安排并继续轮询,从而100%利用1个核心。
使调用线程执行到另一个准备在当前处理器上运行的线程。 操作系统选择要生成的线程。
Thread.Sleep将调度您的线程在睡眠时间到期后再次运行,从而大大降低CPU利用率。
阻止当前线程达到指定的毫秒数。
鉴于两者之间的选择, Thread.Sleep
更适合您的任务。 但是,我同意@Bryan的评论,即Threading.Timer
可以提供更优雅的解决方案。
为帖子回答这个问题:
这样的事情的最佳做法是什么?
您似乎有SpinWait 结构的案例,该结构自 .NET 4.0 起就存在,并且与更旧的SpinWait 方法不同。
你的代码可以升级到这样的:
var timeout = DateTime.Now.AddSeconds(3);
var spinWait = new SpinWait();
while (System.Status != Status.Complete
&& DateTime.Now < timeout
&& !_Worker.CancellationPending)
{
spinWait.SpinOnce();
}
SpinOnce
方法将决定是调用Thread.Sleep
、 Thread.Yield
还是在没有 yield 的情况下进行“忙等待”。
具体关于帖子标题(即Thread.Sleep vs Thread.Yield),这里有一些最新的答案:
SpinWait
慢。 在 Windows 系统上,它(在撰写本文时)实现为对 Win32 API SwitchToThread的调用。Thread.Yield()
相同,除了它允许切换 CPU 内核,这往往会在恢复之前为具有相同或更低优先级的线程提供更多时间。 除了这个额外的时间,在不同的 CPU 内核上恢复的几率要大得多,导致 L1 或 L2 缓存等内容丢失,并进一步降低性能。 仅当饥饿几率高于使用Thread.Yield()
时才应使用它。 在 Windows 系统上,它(在撰写本文时)实现为对 Win32 API SleepEx的调用。Thread.Yield()
和Thread.Sleep(0)
不同, Thread.Sleep(1)
保证在一段时间内放弃 CPU,这可能会使事情降温。 然而,性能成本是巨大的,因此它只能与其他“旋转”或“屈服”解决方案结合使用。对此的补充评论:
但是 CPU 百分比的峰值困扰着我
从您的帖子来看,这种担忧可能是因为代码有 3 秒超时。 SpinWait
应该解决这个问题,但由于某种原因您不能使用SpinWait
结构,请考虑使用较小的超时,以毫秒为单位。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.