从MSDN上看,它的目的并不是很清楚。
它能用来模拟强大的 CPU 计算测试吗?
当您进行多线程锁定时,如果您要获取的资源已经被锁定,通常会进入睡眠状态并等待其变为可用。这样做时,您放弃了调度程序分配给您的其余时间,以便其他人可以使用处理器。 通常情况下,这是可以接受的,特别是对于长时间等待,比如等待IO,当您等待磁盘旋转时,许多其他进程可以在CPU上运行。
然而,有时候,您只需要等待很短的时间。在这种情况下,您通常会放弃剩余时间并等待所有其他线程完成工作,然后再获取机会。因此,您可以采取一种欺骗性的策略,而不是等待,您以“我们快到了吗?”的方式持续地轮询。如果锁仅保持了您剩余时间的一小部分,那么这将成为一种非常有效的等待方式,同时也非常高效,因为如果您正常等待,调度程序不必参与重新安排所有其他线程来使用您放弃的时间。
显然,如果每次想要锁定时都进行自旋,您将不会受到欢迎,您的应用程序将变得缓慢并且使用100%的CPU,但是在正确的时间以非常小的量使用它,则可以使应用程序更加响应。
如果您现在想“何时使用它?”,那么这是一个棘手的问题-如果您有一个经常被快速锁定和解锁的资源,那么在其周围使用自旋锁而不是等待是一个好主意(然后测试您的应用程序的性能),如果您尝试自旋一小段时间,然后回到正常的等待,也是一个合理的方法。但通常情况下,您永远不需要使用它。
目的是在您认为正在等待的条件非常非常快就会成立时进行“廉价”等待。通常情况下,如果您正在等待某些事情,您会让线程进入睡眠状态,处理器/操作系统将切换到另一个线程。上下文切换并不特别廉价,因此,如果您对情况有深入了解并且相信等待比上下文切换更便宜,则可以自旋等待。
我的建议是:如果您需要询问,那么您不需要使用它。 (我自己从未想要过。)基本上,这是一种在非常少数情况下非常有用的东西,但大多数人应该远离它。
Render()
循环内使用异常来限制帧率。其他任何Sleep()
机制都无法提供足够好的保证,确保你会在何时被切换回来。 - BasicThread.Sleep()
,因为它非常不准确(取决于CPU负载,误差可达±25毫秒),因为Windows是一个多任务操作系统。我使用以下代码来计时相关和短暂的睡眠间隔,仅为几毫秒。// IMPORTANT:
// Use this only for very short sleep intervals.
// One CPU core will run with 100% load during this interval.
public static void SleepPrecise(int s32_Interval) // in ms
{
if (s32_Interval <= 0)
return;
// System.Diagnostics.Stopwatch uses the performance counter in the processor
// which has a precision of micro seconds or even nano seconds.
Stopwatch i_Watch = new Stopwatch();
i_Watch.Start();
while (i_Watch.ElapsedMilliseconds < s32_Interval)
{
// SpinWait(80000) --> 1 ms on a 3.6 GHz AMD Radeon processor
Thread.SpinWait(5000);
}
}
如果您需要极高的时间精度,您还可以:
Thread.CurrentThread.Priority = ThreadPriority.Highest;
try
{
.... execute your timing relevant code
}
finally
{
Thread.CurrentThread.Priority = ThreadPriority.Normal;
}
SpinWait
很少会导致CPU利用率达到100%而使你卡住。这是因为如果它旋转的时间太长,它会开始让线程yield
或sleep
。具体来说,如果旋转次数大于或等于10,则每19次旋转就会sleep(1)
,每4次旋转就会sleep(0)
,并且仅当下一次旋转确定具有让出潜力时才会yield
。在多处理器系统上,它可以在任何时候sleep
或yield
,不需要等待最初的10次旋转。在单处理器系统上,只有在旋转计数小于或等于10时,它才会sleep
或yield
。 - Michael J. GrayThread.SpinWait()
(问题和答案)与var sw = new SpinWait(); sw.SpinOnce();
,后者会在内部自旋计数达到10次。 - DeepSpace101