C# 旋转等待vs睡眠等待。用哪一个?

C# 旋转等待vs睡眠等待。用哪一个?,c#,multithreading,C#,Multithreading,这样做有效吗 SpinWait.SpinUntil(() => myPredicate(), 10000) 对于10000毫秒的超时 或 在相同条件下使用Thread.Sleep轮询是否更有效 例如,以下SleepWait函数的内容: public bool SleepWait(int timeOut) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); while (!myPredicate(

这样做有效吗

SpinWait.SpinUntil(() => myPredicate(), 10000)
对于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()
}
public bool SleepWait(int超时)
{
秒表秒表=新秒表();
秒表。开始();
而(!myPredicate()&&stopwatch.ElapsedMilliseconds
我担心的是,如果我们谈论超过1秒的超时,SpinWait的所有收益可能都不是一个好的使用模式?这是一个有效的假设吗

你喜欢哪种方法?为什么?还有其他更好的方法吗


更新-变得更加具体:

有没有办法让BlockingCollection Pulse在达到有限容量时成为休眠线程?正如马克·格拉斯建议的那样,我宁愿避免一起忙碌的等待

最好的方法是使用某种机制来主动检测事物变为真(而不是被动地轮询它变为真);这可能是任何类型的等待句柄,也可能是带有
wait
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);
    }
}
使用,在“放回集合”代码中:


在.NET4
SpinWait
中,在屈服之前执行10次CPU密集型旋转。但它不会在每次循环后立即返回调用方;相反,它调用
Thread.SpinWait
通过CLR(本质上是操作系统)在设定的时间段内旋转。这个时间段最初是几十纳秒,但每次迭代都会加倍,直到10次迭代完成。这使得总旋转时间(CPU密集型)阶段清晰/可预测,系统可根据条件(内核数量等)进行调整。如果
SpinWait
在自旋产生阶段停留的时间过长,它将定期休眠以允许其他线程继续(有关更多信息,请参阅)。此过程保证使核心保持忙碌

因此,
SpinWait
将CPU密集型旋转限制为一组迭代次数,之后每次旋转都会产生时间片(通过实际调用
Thread.Yield
Thread.Sleep
),从而降低资源消耗。它还将检测用户是否正在运行单核机器,如果是这样,则在每个循环中都会进行让步


使用
线程。睡眠
线程被阻塞。但是这个过程在CPU方面不会像上面那样昂贵。

谢谢,我喜欢你的回答,这确实很好。假设您正在通过BlockingCollection跟踪某些资源的使用情况。它们会被使用(并从集合中删除)并在可再次使用时返回集合。只有当所有这些都返回到集合中时,才会发生关闭。除了忙着等待之外,你会如何发出关闭的信号(即收集又满了)?@Anastasiosyal我会封装收集,让包装器在满的时候做一些事情;实际上,我可能会在从BlockingQueue派生的“ObjectPool”类的析构函数中使用
监视器(将添加示例),逐个弹出BlockingCollection中的所有对象并对其进行处理(因为这是C#,所以将检索到的引用设置为nil),直到弹出的对象数等于池深度。所有池对象都已被释放,因此您可以释放队列并从dtor返回以继续关闭序列。无需轮询/忙碌等待!您可能希望在拍摄时设置一些超时,以便泄漏的对象最终引发异常(或其他情况)。@MartinJames-对于大多数情况,这是一个有效的注释。在这种情况下,集合的所有者没有被销毁,而是返回到一个池中(想想会话关闭和会话返回到池中)@Anastasiosyal我的道歉-它是
监视器。等等
-但否:它不会死锁;这是将监视器用作信号的常用技术
Wait
在持续时间内释放锁,然后在返回true或false之前重新获取锁。这是从Albahari的网站复制的。它应该被引用!它不是逐字复制的,而是受他的网站影响的,所以我引用了他的博客。谢谢你的解释,它真的很有用。
if(CollectionIsFull) {
    lock(syncLock) {
        if(CollectionIsFull) { // double-check with the lock
            Monitor.PulseAll(syncLock);
        }
    }
}