在進行多線程開發時,我們經常會用到Thread.Sleep(timeout_ms)來等待或者騰出時間來讓其他線程處理。不過,即使我們把timeout_ms設置爲0,Thread.Sleep還是會執行等待操作。這就讓人很納悶了,我明明指定的等待時間是0毫秒,爲什麼還會執行等待呢?
這時因爲當我們調用Thread.Sleep時,是讓內核暫停處理當前的線程,然後再看需要等待多久,當發現等待時間是timeout_ms時,就等待timeout_ms長的時間,然後內核繼續運行該線程。即使timeout_ms爲0,由於這個過程中內核已經執行了暫停和恢復的動作,所以會消耗時間。這樣也就說明了,即時Thread.Sleep等待的時候是0,還是會有等待的過程。
而如果使用自旋等待就會不一樣。下面先看一下代碼和執行結果。
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Linq;
- using System.Text;
- using System.Threading;
- namespace SpinWaitTest
- {
- class Program
- {
- private static int _count = 1000;
- private static int _timeout_ms = 10;
- static void Main(string[] args)
- {
- //NoSleep();
- ThreadSleepInThread();
- SpinWaitInThread();
- Console.ReadLine();
- }
- private static void NoSleep()
- {
- Thread thread = new Thread(() =>
- {
- var sw = Stopwatch.StartNew();
- for (int i = 0; i < _count; i++)
- {
- }
- Console.WriteLine("No Sleep Consume Time:{0}", sw.Elapsed.ToString());
- });
- thread.IsBackground = true;
- thread.Start();
- }
- private static void ThreadSleepInThread()
- {
- Thread thread = new Thread(() =>
- {
- var sw = Stopwatch.StartNew();
- for (int i = 0; i < _count; i++)
- {
- Thread.Sleep(_timeout_ms);
- }
- Console.WriteLine("Thread Sleep Consume Time:{0}", sw.Elapsed.ToString());
- });
- thread.IsBackground = true;
- thread.Start();
- }
- private static void SpinWaitInThread()
- {
- Thread thread = new Thread(() =>
- {
- var sw = Stopwatch.StartNew();
- for (int i = 0; i < _count; i++)
- {
- SpinWait.SpinUntil(() => true, _timeout_ms);
- }
- Console.WriteLine("SpinWait Consume Time:{0}", sw.Elapsed.ToString());
- });
- thread.IsBackground = true;
- thread.Start();
- }
- }
- }
看看結果會發現,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