简体   繁体   English

Thread.Sleep 或 Thread.Yield

[英]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.SleepThread.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),这里有一些最新的答案:

  • Thread.Yield() : If there is another thread ready to execute, then this gives away the current CPU core to that thread. Thread.Yield() :如果有另一个线程准备好执行,那么这会将当前的 CPU 核心交给该线程。 Otherwise does nothing, ie returns immediately, which may cause high CPU (and high battery consumption) if the system has at least one idle CPU core.否则什么都不做,即立即返回,如果系统至少有一个空闲的 CPU 内核,这可能会导致 CPU 高(和电池消耗高)。 In most cases, resumes execution in the same CPU core, but this is not guaranteed for a number of reasons (the thread might be suspended by GC, etc).在大多数情况下,会在同一个 CPU 内核中恢复执行,但由于多种原因(线程可能被 GC 挂起等),这并不能保证。 On server space, it's a great way to implement a simple busy wait, but it may be slower than the above explained SpinWait in some cases.在服务器空间上,这是实现简单繁忙等待的好方法,但在某些情况下它可能比上面解释的SpinWait慢。 On Windows systems, it is (as of this writing) implemented as call to Win32 API SwitchToThread .在 Windows 系统上,它(在撰写本文时)实现为对 Win32 API SwitchToThread的调用。
  • Thread.Sleep(0) : Puts the current thread in the end of OS ready-to-execute queue for that priority, if the queue is not empty. Thread.Sleep(0) :如果队列不为空,则将当前线程置于该优先级的 OS 准备执行队列的末尾。 Otherwise does nothing, ie returns immediately.否则什么都不做,即立即返回。 The behavior is almost identical to 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.除了这个额外的时间,在不同的 CPU 内核上恢复的几率要大得多,导致 L1 或 L2 缓存等内容丢失,并进一步降低性能。 It should be used only when odds of starvation are higher than using Thread.Yield() .仅当饥饿几率高于使用Thread.Yield()时才应使用它。 On Windows systems, it is (as of this writing) implemented as call to Win32 API SleepEx .在 Windows 系统上,它(在撰写本文时)实现为对 Win32 API SleepEx的调用。
  • Thread.Sleep(1) : If the remainder of the timeslice has at least 1ms, gives the CPU away for the remainder of the timeslice. Thread.Sleep(1) :如果剩余的时间片至少有 1 毫秒,则为剩余的时间片让出 CPU。 Otherwise, gives the CPU away for the remainder of the timeslice AND the entire next timeslice.否则,将 CPU 用于剩余时间片和整个下一个时间片。 Because in many systems the timeslice is about 15ms, it tends to sleep for about 7ms or 8ms in average .因为在许多系统中时间片大约为 15 毫秒,它倾向于平均睡眠大约 7 毫秒或 8 毫秒。 Therefore, different than 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM