SpinWait的性能高於Thread.Sleep

在進行多線程開發時,我們經常會用到Thread.Sleep(timeout_ms)來等待或者騰出時間來讓其他線程處理。不過,即使我們把timeout_ms設置爲0,Thread.Sleep還是會執行等待操作。這就讓人很納悶了,我明明指定的等待時間是0毫秒,爲什麼還會執行等待呢?

這時因爲當我們調用Thread.Sleep時,是讓內核暫停處理當前的線程,然後再看需要等待多久,當發現等待時間是timeout_ms時,就等待timeout_ms長的時間,然後內核繼續運行該線程。即使timeout_ms爲0,由於這個過程中內核已經執行了暫停和恢復的動作,所以會消耗時間。這樣也就說明了,即時Thread.Sleep等待的時候是0,還是會有等待的過程。

而如果使用自旋等待就會不一樣。下面先看一下代碼和執行結果。

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Diagnostics;  
  4. using System.Linq;  
  5. using System.Text;  
  6. using System.Threading;  
  7.   
  8. namespace SpinWaitTest  
  9. {  
  10.     class Program  
  11.     {  
  12.         private static int _count = 1000;  
  13.         private static int _timeout_ms = 10;  
  14.   
  15.         static void Main(string[] args)  
  16.         {  
  17.             //NoSleep();  
  18.             ThreadSleepInThread();  
  19.             SpinWaitInThread();  
  20.             Console.ReadLine();  
  21.         }  
  22.   
  23.         private static void NoSleep()  
  24.         {  
  25.             Thread thread = new Thread(() =>  
  26.             {  
  27.                 var sw = Stopwatch.StartNew();  
  28.                 for (int i = 0; i < _count; i++)  
  29.                 {  
  30.                      
  31.                 }  
  32.                 Console.WriteLine("No Sleep Consume Time:{0}", sw.Elapsed.ToString());  
  33.             });  
  34.             thread.IsBackground = true;  
  35.             thread.Start();  
  36.         }  
  37.   
  38.         private static void ThreadSleepInThread()  
  39.         {  
  40.             Thread thread = new Thread(() =>  
  41.             {  
  42.                 var sw = Stopwatch.StartNew();  
  43.                 for (int i = 0; i < _count; i++)  
  44.                 {  
  45.                     Thread.Sleep(_timeout_ms);  
  46.                 }  
  47.                 Console.WriteLine("Thread Sleep Consume Time:{0}", sw.Elapsed.ToString());  
  48.             });  
  49.             thread.IsBackground = true;  
  50.             thread.Start();  
  51.         }  
  52.   
  53.         private static void SpinWaitInThread()  
  54.         {  
  55.             Thread thread = new Thread(() =>  
  56.             {  
  57.                 var sw = Stopwatch.StartNew();  
  58.                 for (int i = 0; i < _count; i++)  
  59.                 {  
  60.                     SpinWait.SpinUntil(() => true, _timeout_ms);  
  61.                 }  
  62.                 Console.WriteLine("SpinWait Consume Time:{0}", sw.Elapsed.ToString());  
  63.             });  
  64.             thread.IsBackground = true;  
  65.             thread.Start();  
  66.         }  
  67.     }  
  68. }  
運行結果

看看結果會發現,Thread.Sleep的時間比SpinWait多了近50萬倍,這相差實在是太大了。有人會說了,Thread.Sleep是執行了10ms*1000=10s的等待,而SpinWait.SpinUntil的條件直接是true,所以相當於沒有等待,時間自然會少了很多。那好,我們把_timeout_ms設成0,然後再看運行結果。


我們看到Thread.Sleep的等待時間還是要比SpinWait的長了近10倍,這是爲什麼呢?

這是因爲SpinWait.SpinUntil在執行等待時,會先進行自旋。所謂自旋就是在CPU運轉的週期內,如果條件滿足了,就不會再進入內核等待(即暫停該線程,等待一段時間後,再繼續運行該線程),如果條件不滿足,才進入內核等待。這樣一來,SpinWait會比Thread.Sleep多運行一次的CPU週期,再進入等待。因爲CPU週期是很短的(現在一般的電腦都有2.1GHZ以上),所以這個等待對時間影響不大,卻可以提升很大的性能。

可以參看MSDN的說明http://msdn.microsoft.com/zh-cn/library/system.threading.thread.spinwait(v=vs.110).aspx

發佈了76 篇原創文章 · 獲贊 188 · 訪問量 184萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章