這會消耗接近零的CPU(酷睿i5系列)C#SpinWait長期等待
public void SpinWait() {
for (int i = 0; i < 10000; i++)
{
Task.Factory.StartNew(() =>
{
var sw = new SpinWait();
while (true)
{
sw.SpinOnce();
}
});
}
}
在我的代碼的性能差異比較SemaphoreSlim是的情況下3倍倍以上旋轉時真的是有道理的(5 MOPS)。但是,我擔心使用它進行長期等待。標準的建議是實施兩階段等待操作。我可以檢查NextSpinWillYield
屬性,並引入一個計數器+重置來增加默認的旋轉迭代而不屈服,並且退回到信號量。
但長期等待使用SpinWait.SpinOnce
的缺點是什麼?我已瀏覽了其implementation,並在需要時正確收益。它使用Thread.SpinWait
,在現代CPU上使用PAUSE指令,根據Intel,它非常高效。
我在監視任務管理器時發現的一個問題是,如果由於默認的ThreadPool算法逐漸增加(當所有任務繁忙時它每秒都會添加一個線程),線程數量會逐漸增加。這可以通過使用ThreadPool.SetMaxThreads
來解決,然後線程的數量是固定的,並且CPU使用率仍然接近零。
如果長期等待任務的數量是有限的,那麼使用SpinWait.SpinOnce
進行長期等待還有什麼其他缺陷。它依賴於CPU系列,操作系統,.NET版本嗎?
(只是爲了澄清:我還是會執行兩階段的等待,我只是珍玩爲什麼不使用SpinOnce所有的時間)
謝謝!順便說一下,多少微秒需要線程喚醒,例如如果我等着'semaphore.WaitAsync(-1,token)'?如果我使用'Sleep(1)'進行spinwait和'SpinOne'產生,那麼在最壞的情況下,如果一個信號在調用'Sleep(1)'後到達,至少會引入'15毫秒的延遲。如果我改用信號量,那麼線程在信號量喚醒後的最壞情況下的延遲是什麼?釋放()'? –
這很大程度上取決於機器上還發生了什麼。當然,您還必須與其他進程和內核線程擁有的線程競爭。它需要幾微秒,而不是幾毫秒。只需用秒錶來測量它,由於偶爾的最壞情況可能會很長,所以一定要採取多次測量的中位數。請記住,你無法做任何事情,所以它只是信息。切勿使用Sleep()。 –
因此,信號量釋放之後醒來與.NET無關,使用C/C++甚至程序集都無濟於事? (不會使用它們,只是爲了解這是硬件/操作系統設計) –