V.B*_*.B. 6 .net c# multithreading
此代码消耗接近零CPU(i5系列)
public void SpinWait() {
for (int i = 0; i < 10000; i++)
{
Task.Factory.StartNew(() =>
{
var sw = new SpinWait();
while (true)
{
sw.SpinOnce();
}
});
}
}
Run Code Online (Sandbox Code Playgroud)
在我的代码中,与SemaphoreSlim相比,性能差异是旋转真正合理(5 Mops)的情况下的3倍或更多.但是,我担心使用它进行长期等待.标准建议是实现两阶段等待操作.我可以检查NextSpinWillYield
属性并引入一个计数器+重置来增加默认的旋转迭代而不会屈服,而不是退回到信号量.
但是,仅仅SpinWait.SpinOnce
用于长期等待的缺点是什么?我已经查看了它的实现,并在需要时正确地生成了它.它使用Thread.SpinWait
现代CPU使用PAUSE指令,并且根据英特尔的说法非常有效.
我在监视任务管理器时发现的一个问题是,由于默认的ThreadPool算法逐渐增加线程数(它在所有任务繁忙时每秒添加一个线程).这可以通过使用来解决ThreadPool.SetMaxThreads
,然后修复线程数并且CPU使用率仍接近零.
如果长期等待任务的数量有限,那么使用SpinWait.SpinOnce
长期等待的其他陷阱是什么.它是否依赖于CPU系列,OS,.NET版本?
(只是为了澄清:我仍然会实现两阶段等待,我只是好奇为什么不一直使用SpinOnce?)
Han*_*ant 10
好吧,正面就是你看到的那个,你的代码占用了一个线程而没有完成任何事情.防止其他代码运行并强制线程池管理器对其执行某些操作.修补ThreadPool.SetMaxThreads()只是一个可能是一个大量出血伤口的创可贴,只有在你需要赶飞机回家时才使用它.
只有在非常好地保证这样做比线程上下文切换更有效时,才应该尝试旋转.这意味着您必须确保线程可以在大约10,000 cpu周期内继续运行.这只是5 微秒,给予或接受,比大多数程序员认为的"长期"更少.
使用将触发线程上下文切换的同步对象.或lock
关键字.
这不仅会产生处理器,因此其他等待线程可以完成工作,从而完成更多工作,它还为OS线程调度程序提供了极好的提示.发出信号的同步对象将突破线程的优先级,因此很可能会使处理器接下来.
归档时间: |
|
查看次数: |
711 次 |
最近记录: |