【问题标题】:What's the purpose of Thread.SpinWait method?Thread.SpinWait 方法的目的是什么?
【发布时间】:2009-07-07 08:56:48
【问题描述】:

来自MSDN 并不是很清楚它的用途。

可以用来模拟密集的CPU计算测试吗?

【问题讨论】:

    标签: .net multithreading


    【解决方案1】:

    没有。它用作非常短期的睡眠电话的替代品。

    当您执行多线程锁定时,如果您尝试获取的资源已被锁定,您通常会进入睡眠状态并等待它变得空闲。当你这样做时,你放弃了调度程序分配给你的剩余时间来使用处理器,以便其他人可以尝试。 通常这很好,特别是对于长时间的等待,比如等待 IO,在等待磁盘主轴旋转时,其他进程的负载可以在 CPU 上运行。

    但是,有时,您需要等待很短的时间。在这些情况下,您通常会放弃剩余的时间,并等待所有其他线程完成他们的工作,然后再进行另一次尝试。所以您可以作弊,而不是等待,您坐在那里不断轮询“我们快到了吗?有吗?方式。如果锁只保留了你剩余时间的一小部分,这将成为一种非常有效的等待方式,它也非常有效,因为调度程序不必参与重新安排所有其他线程来使用你放弃的时间如果你正常等待。

    显然,如果您每次想要锁定时都旋转,那么您将不会很受欢迎,您的应用程序会变得迟缓并使用 100% 的 CPU,但是在非常小的剂量下,在正确的时间,它会使应用响应更快。

    如果您现在正在考虑“我应该什么时候使用它?”,这是一个棘手的调用 - 如果您的资源经常被锁定和解锁非常快,那么围绕它的自旋锁而不是等待是一个好主意(然后测试您的应用程序的性能),如果您尝试短时间旋转,然后回到正常等待,这也是一种合理的方式。但一般来说,您永远不需要使用它。

    【讨论】:

    • 假设我们要实现平均 50ms 的延迟,我们指定多少次迭代?
    • SpinWait 很少会导致您卡在 100% 的 CPU 利用率上。这是因为如果它旋转太久,它开始导致线程屈服或休眠。具体来说,如果旋转次数大于或等于 10,则每 19 次旋转将sleep(1),每 4 次旋转将sleep(0),并且当且仅当确定下一次旋转具有屈服潜力时yield .它可以在任何时候在多处理器系统上sleepyield,并且不需要等待最初的 10 次旋转。在单处理器系统上,只有在旋转计数为 10 或以下时才会sleepyield
    • @MichaelJ.Gray:您将Thread.SpinWait()(问题和答案)与var sw = new SpinWait(); sw.SpinOnce(); 混淆了,后者将内部旋转计数到10 ...
    • @CharlesOkwuagwu 持续几十毫秒,你最好用一个简单的 thread.sleep。
    • @StephenKennedy “数十毫秒”,您绝对会(不太可能)使用简单的 thread.sleep。现代处理器可以在几十毫秒内在单个内核上执行数百万条指令。
    【解决方案2】:

    如果您相信您等待的条件会非常非常快实现,那么目的是进行“廉价”等待。通常,如果您正在等待某些东西,您会让线程进入睡眠状态,处理器/操作系统将上下文切换到另一个线程。上下文切换并不是特别便宜,所以如果您对情况有深入的了解,并且认为等待比上下文切换更便宜,那么您就可以等待。

    我的建议:如果你需要问,你不需要使用它。 (我自己从来不想要它。)基本上它是在极少数情况下真正有用的东西之一,但大多数人应该别管它。

    【讨论】:

    • 我猜这个和“除非你已经测量并发现有问题......”的整个类别一致
    • @jon skeet 因此,默认情况下,您会建议简单地使用 lock(obj) 并且仅在您通过基准测试确定它对您的场景更快时才使用 spinwait?
    • @rolls:是的,绝对是。这是一个非常小众的功能。
    【解决方案3】:

    附带说明,Microsoft 已经从 Windows 7 中删除了线程调度程序自旋锁机制,因为它不能很好地扩展到多核 CPU。看看this

    【讨论】:

    • 它说他们已经摆脱了他们在 Windows 中使用的一个自旋锁——调度程序自旋锁。
    【解决方案4】:

    就我而言(我很高兴进行更正!),自旋等待的唯一用途是在实现锁定或线程间回调机制时。并且两者都不应该手动完成(通常),因为它们已经存在。

    当你锁定一个资源并且另一个线程请求同步访问它时,它基本上必须等待第一个线程完成使用它。这种等待可以通过简单地循环来完成(或者乔恩提到的睡眠+上下文切换)。

    【讨论】:

    • 一个例外 - 在游戏引擎的 Render() 周期内限制帧速率。其他Sleep() 机制都没有提供足够好的保证您何时会被切换回来。
    • @Basic 是的,尽管通常会在渲染周期中跳过几圈而不是显式(嵌套)等待循环。效果当然是一样的。
    猜你喜欢
    • 2021-12-23
    • 2010-09-07
    • 2020-04-25
    • 1970-01-01
    • 1970-01-01
    • 2012-03-22
    • 2017-01-20
    • 1970-01-01
    相关资源
    最近更新 更多