SpinWait与睡眠等待.哪一个使用?

Ana*_*yal 70 c# multithreading

是否有效率

SpinWait.SpinUntil(() => myPredicate(), 10000)
Run Code Online (Sandbox Code Playgroud)

超时10000毫秒

要么

Thread.Sleep在相同条件下使用轮询是否更有效例如,以下SleepWait函数的行:

public bool SleepWait(int timeOut)
{
    Stopwatch stopwatch = new Stopwatch(); 
    stopwatch.Start();
    while (!myPredicate() && stopwatch.ElapsedMilliseconds < timeOut)
    {
       Thread.Sleep(50)
    }  
    return myPredicate()
}
Run Code Online (Sandbox Code Playgroud)

我担心如果我们谈论超过1秒的超时,SpinWait的所有收益可能都不是一个好的使用模式?这是一个有效的假设吗?

您更喜欢哪种方法?为什么?还有另一种更好的方法吗?


更新 - 变得更具体:

有没有办法让BlockingCollection Pulse在达到有界容量时成为睡眠线程?正如Marc Gravel建议的那样,我宁愿避免忙碌等待.

Moo*_*ght 125

在.NET 4中SpinWait,在屈服之前执行10次迭代的CPU密集型旋转.但是在每个周期之后它不会立即返回给调用者; 相反,它调用Thread.SpinWait通过CLR(本质上是OS)旋转一段时间.该时间段最初为几十纳秒,但每次迭代加倍,直到10次迭代完成.这使得旋转(CPU密集型)阶段所花费的总时间的清晰度/可预测性成为可能,系统可以根据条件(核心数等)进行调整.如果SpinWait在旋转产生阶段停留太长时间,它将定期休眠以允许其他线程继续进行(有关更多信息,请参阅J. Albahari的博客).这个过程保证让核心忙碌......

因此,SpinWait将CPU密集型旋转限制为设定的迭代次数,之后它会在每次旋转(通过实际调用Thread.YieldThread.Sleep)时产生时间片,从而降低其资源消耗.如果是这种情况,它还将检测用户是否正在运行单个核心机器并在每个周期产生.

随着Thread.Sleep线程被阻止.但就CPU而言,这个过程不会像上面那样昂贵.

  • +1感谢SpinWait和thread.Sleep之间的清晰度 (10认同)
  • 它不是逐字复制的,而是受到他的网站的影响,因此我引用了他的博客。 (4认同)

Mar*_*ell 46

最好的办法是有一些机制来主动检测的东西变成真正的(而不是被动地轮询它已经成为真正的); 这可能是任何类型的等待句柄,或者一个TaskWait,也许一个event,你可以订阅扯去自己.当然,如果你做那种"等到事情发生",那仍然不如仅仅将下一部分工作作为回调完成那样有效,这意味着:你不需要使用线程来等待.TaskContinueWith这个,或者你可以event在它被解雇时做的工作.这event可能是最简单的方法,具体取决于上下文.Task然而,已经提供了你在这里谈论的大部分内容,包括"等待超时"和"回调"机制.

是的,旋转10秒并不是很好.如果你想使用类似当前代码的东西,并且你有理由期望短暂的延迟,但是需要允许更长的延迟 - 也许SpinWait是(比方说)20ms,并Sleep用于其余的?


重新评论; 这是我如何勾选"它是完整的"机制:

private readonly object syncLock = new object();
public bool WaitUntilFull(int timeout) {
    if(CollectionIsFull) return true; // I'm assuming we can call this safely
    lock(syncLock) {
        if(CollectionIsFull) return true;
        return Monitor.Wait(syncLock, timeout);
    }
}
Run Code Online (Sandbox Code Playgroud)

用,在"放回集合"代码:

if(CollectionIsFull) {
    lock(syncLock) {
        if(CollectionIsFull) { // double-check with the lock
            Monitor.PulseAll(syncLock);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,我喜欢你的回答,这确实很好。假设您正在通过 BlockingCollection 跟踪某些资源的使用。它们被使用(并从集合中删除)并在它们再次可用以供重用时返回到集合。只有当所有这些都返回到集合中时才会发生关闭。除了忙等待之外,您将如何发出可以继续关闭的信号(即收集已满)? (2认同)
  • @Anastasiosyal我的道歉 - 它是`Monitor.Wait` - 但不是:它不会死锁; 这是使用监视器作为信号的正常和常用技术.`Wait`释放锁定持续时间,然后**重新获取**锁定,然后返回true或false. (2认同)