利用Spinwait來達到效能提升

  • 66
  • 0
  • C#
  • 2023-08-26

利用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,避免自旋佔住執行緒太久。

Thread.Sleep與Spinwait皆是同步鎖定當前執行緒。