gpt4 book ai didi

C# SpinWait 实现长时间等待

转载 作者:太空狗 更新时间:2023-10-29 21:12:11 27 4
gpt4 key购买 nike

此代码消耗接近零的 CPU(i5 系列)

    public void SpinWait() {

for (int i = 0; i < 10000; i++)
{
Task.Factory.StartNew(() =>
{
var sw = new SpinWait();
while (true)
{
sw.SpinOnce();
}
});
}
}

在我的代码中,与 SemaphoreSlim 相比,在旋转确实合理(5 Mops)的情况下,性能差异是 3 倍或更多。但是,我担心将其用于长期等待。标准建议是实现两阶段等待操作。我可以检查 NextSpinWillYield 属性并引入一个 counter+reset 来增加默认的旋转迭代而不屈服,而不是退回到信号量。

但是仅使用 SpinWait.SpinOnce 进行长期等待有什么缺点呢?我看过它的 implementation并在需要时适本地产生。它使用 Thread.SpinWait,它在现代 CPU 上使用 PAUSE 指令并且根据 Intel 非常有效。 .

我在监控任务管理器时发现的一个问题是,由于默认的 ThreadPool 算法,线程数逐渐增加(当所有任务都忙时,它每秒添加一个线程)。这可以通过使用 ThreadPool.SetMaxThreads 来解决,然后线程数是固定的,CPU 使用率仍然接近于零。

如果长时间等待任务的数量是有限的,那么使用 SpinWait.SpinOnce 进行长期等待的其他陷阱是什么?它取决于 CPU 系列、操作系统、.NET 版本吗?

(澄清一下:我仍然会实现两阶段等待,我只是好奇为什么不一直使用 SpinOnce?)

最佳答案

好吧,不利的一面正是您所看到的,您的代码占用了一个线程而没有完成任何事情。阻止其他代码运行并强制线程池管理器对此做一些事情。修补 ThreadPool.SetMaxThreads() 只是对可能流血过多的伤口的创可贴,只有在您需要赶飞机回家时才使用它。

只有当您可以很好地保证这样做比线程上下文切换有效时,才应该尝试自旋。这意味着您必须确保线程可以在大约 10,000 个 cpu 周期或更少的时间内继续。这只有 5 微秒,无论多少,都比大多数程序员认为的“长期”要少很多。

改为使用将触发线程上下文切换的同步对象。或者 lock 关键字。

这不仅会产生处理器以便其他等待的线程可以完成他们的工作,从而完成更多的工作,它还为 OS 线程调度程序提供了一个极好的提示。发出信号的同步对象会影响线程的优先级,因此很可能会获得下一个处理器。

关于C# SpinWait 实现长时间等待,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36618304/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com