利用Spinwait來達到效能提升
一般我們要寫一個定時多久去執行一件事的程式時,可能會寫無窮迴圈 + Thread.Sleep,去等待多久執行一次,程式碼可能如下:
Thread版本:
namespace UseSpinwait
{
class Program
{
private static volatile bool _stop = false;
static void Main(string[] args)
{
var th = new Thread(RunLoop);
th.Start();
Console.WriteLine("enter to abort");
Console.ReadLine();
_stop = true;
Console.ReadLine();
}
static void RunLoop()
{
while (true)
{
Thread.Sleep(10); //等10ms執行下面程式
Console.WriteLine(DateTime.Now);
if (_stop == true)
break;
}
Console.WriteLine("exit thread");
}
}
}
而CPU使用的情況:
Spinwait版本:
namespace UseSpinwait
{
class Program
{
private static volatile bool _stop = false;
static void Main(string[] args)
{
var th = new Thread(RunLoop);
th.Start();
Console.WriteLine("enter to abort");
Console.ReadLine();
_stop = true;
Console.ReadLine();
}
static void RunLoop()
{
while (true)
{
SpinWait.SpinUntil(() => _stop, 10); //_stop為true或等10ms條件成立,則程式往下走
Console.WriteLine(DateTime.Now.ToLongTimeString());
if (_stop == true)
break;
}
Console.WriteLine("exit thread");
}
}
}
而CPU使用的情況:
根據上面數據顯示當在短時間等待時Spinwait占用CPU資源會比Thread來的少很多,原因是在Thread.Sleep時會暫停執行緒,而到等待的時間被滿足,在喚醒當前執行緒,因此在無窮迴圈情況下,Thread.Sleep只有10ms,所以短時間CPU會一直做context switch暫停在喚醒執行緒,因此消耗許多CPU效能,而當使用Spinwait則是自旋,自旋意思就是執行緒會空轉等待時間條件被滿足在繼續執行程式,並不會被暫停。
因此當你在使用Spinwait時,需要思考是否大部份的情況下預期等待的時間都很少,可能都少於100ms以下,在考慮用Spinwait,避免自旋佔住執行緒太久。