Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 如果我使用Thread.Sleep(),等待是否真的很忙?_Multithreading_Thread Sleep - Fatal编程技术网

Multithreading 如果我使用Thread.Sleep(),等待是否真的很忙?

Multithreading 如果我使用Thread.Sleep(),等待是否真的很忙?,multithreading,thread-sleep,Multithreading,Thread Sleep,我的问题对定义有点挑剔: 下面的代码可以描述为“忙等待”吗?尽管它使用Thread.Sleep()来允许上下文切换,但它是否仍然可以 while (true) { if (work_is_ready){ doWork(); } Thread.Sleep(A_FEW_MILLISECONDS); } PS-维基百科当前对忙碌等待的定义表明,这是一种“不那么浪费的”忙碌等待形式。这不是忙碌等待。忙碌的等待,或者说旋转,涉及到相反的事情:避免上下文切换 如果要

我的问题对定义有点挑剔:

下面的代码可以描述为“忙等待”吗?尽管它使用Thread.Sleep()来允许上下文切换,但它是否仍然可以

while (true) {
    if (work_is_ready){
        doWork();
    }
    Thread.Sleep(A_FEW_MILLISECONDS);
}

PS-维基百科当前对忙碌等待的定义表明,这是一种“不那么浪费的”忙碌等待形式。

这不是忙碌等待。忙碌的等待,或者说旋转,涉及到相反的事情:避免上下文切换

如果要允许其他线程运行,且仅当其他线程准备好运行时,以避免单线程CPU中出现死锁情况(例如,当前线程需要
work\u已准备好
设置为true,但如果此线程不放弃处理器并让其他线程运行,则永远不会设置为true),您可以使用
Thread.Sleep(0)

一个更好的选择是使用

SpinWait
发出一个特殊的
rep;nop
(重复no op)或
pause
指令,它让处理器知道您正忙着等待,并针对超线程CPU进行了优化。 此外,在单核CPU中,这将
立即产生处理器(因为如果只有一个核,忙等待是完全无用的)


但是,只有当您绝对确定某个条件的等待时间不会超过处理器切换上下文所需的时间时,旋转才有用。也就是说,不超过几微秒

如果您想每隔几毫秒轮询一个条件,那么应该使用blocking synchronization原语,正如wiki页面所建议的那样。对于您的场景,我建议使用,它在调用
WaitOne
时阻塞线程,直到事件发出信号(即,条件变为真)


另请阅读:

任何轮询循环,无论轮询操作之间的时间如何,都是繁忙的等待。诚然,睡眠几毫秒比完全不睡眠要“忙”得多,但它仍然涉及到处理:线程上下文切换和一些最小条件检查

非忙等待是阻塞呼叫。示例的非繁忙版本将涉及等待同步原语,如事件或条件变量。例如,此伪代码:

// initialize an event to be set when work is ready
Event word_is_ready;
work_is_ready.Reset();

// in code that processes work items
while (true)
{
    work_is_ready.Wait();  // non-busy wait for work item
    do_work();
}

这里的区别在于没有定期轮询。
Wait
调用将被阻塞,并且在设置事件之前,不会调度线程。

这取决于操作系统和睡眠的确切毫秒数。如果睡眠时间足够长,操作系统可以切换到另一个任务,填充其缓存,并有效地运行该任务,直到您的任务准备好再次运行,那么它就不会忙于等待。如果不是,那就是

为了批评这段代码,我会这样说:“如果睡眠太小,无法让内核在检查之间执行有用的工作,那么这段代码可能会忙着等待。应该更改它,以便使这段代码需要执行工作的代码触发该响应。”


这种糟糕的设计造成了一个不必要的设计问题——睡眠时间应该有多长?如果太短,你就忙着等。如果时间太长,工作就没有完成。即使等待的时间足够长,也会强制进行不必要的上下文切换。

当代码处于睡眠状态时,从技术上讲,它将处于睡眠状态,从而释放CPU。在忙等待中,代码将占用CPU直到满足条件

下面的代码可以描述为“忙等待”吗?尽管它使用Thread.Sleep()来允许上下文切换,但它是否仍然可以

while (true) {
    if (work_is_ready){
        doWork();
    }
    Thread.Sleep(A_FEW_MILLISECONDS);
}
不是忙着等待,而是轮询,这比忙着等待更有效。两者之间有区别


简单地说,忙等待就是阻塞,因为轮询是非阻塞的

我不认为在“几毫秒”的时间内旋转会更有效率。上下文开关占用核心大约30微秒;在整个等待时间内(3mS==30000微秒),旋转将浪费内核的所有CPU周期。旋转只有在旋转所花费的时间少于进行上下文切换所需的时间时才有意义。@JeremyFriesner你说得绝对正确,我不知道操作要等那么长时间。我很快会更新我的答案。c2.com(它似乎是一个权威的软件设计网站)不同意你的观点。下面是它们的示例:
BusyWaiting:while(MyFileIsNotReady()){//donothing}
和轮询:
while(MyFileIsNotReady()){Sleep(1000);}
。我知道睡眠是唯一的区别。