国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

Thread.Sleep(0)、Thread.Sleep(1)、Thread.Yeild()

2019-11-08 02:04:39
字體:
來源:轉載
供稿:網友

本文轉自:http://www.cnblogs.com/stg609/p/3857242.html。原博主的具體信息參見文章尾部。

本文將要提到的線程及其相關內容,均是指 Windows 操作系統中的線程,不涉及其它操作系統。

  文章索引

  核心概念  Thread.Yeild      Thread.Sleep(0)  Thread.Sleep(1)  實驗告訴你:單一線程  實驗告訴你:多線程(同優先級)  實驗告訴你:多線程(不同優先級)    本人觀點  參考資源

 

  在進入正文前,有幾個知識點需要大家在閱讀前有所了解。

 

核心概念

  優先級調度算法

  處理器是一個操作系統執行任務的工具,線程是一個操作系統執行任務的基本單位,處理器的數量決定了不可能所有線程都能同時得到執行。這就需要通過某種算法來進行任務高度。而 Windows 是一個搶占式的多任務操作系統,我們來看下維基百科對于搶占式的定義:

In computing, PReemption is the act of temporarily interrupting a task being carried out by a computer system, without requiring its coOperation, and with the intention of resuming the task at a later time. Such a change is known as a context switch. It is normally carried out by a privileged task or part of the system known as a preemptive scheduler, which has the power to preempt, or interrupt, and later resume, other tasks in the system.

--- Preemption (computing)

  上面這段英文意味著在搶占式的操作系統中,執行任務的多個線程之間會因為某種因素互相爭搶在處理器上運行的機會。而這種因素就是標題所說的 “優先級”。

 

線程是根據其優先級而調度執行的。 即使線程正在運行時中執行,所有線程都是由操作系統分配處理器時間片的。 用于確定線程執行順序的調度算法的詳細情況隨每個操作系統的不同而不同。

在某些操作系統下,具有最高優先級(相對于可執行線程而言)的線程經過調度后總是首先運行。 如果具有相同優先級的多個線程都可用,則計劃程序將遍歷處于該優先級的線程,并為每個線程提供一個固定的時間片(段)來執行。 只要具有較高優先級的線程可以運行,具有較低優先級的線程就不會執行。 如果在給定的優先級上不再有可運行的線程,則計劃程序將移到下一個較低的優先級并在該優先級上調度線程以執行。 如果此時具有較高優先級的線程可以運行,則具有較低優先級的線程將被搶先,并允許具有較高優先級的線程再次執行。 除此之外,當應用程序的用戶界面在前臺和后臺之間移動時,操作系統還可以動態調整線程優先級。 其他操作系統可以選擇使用不同的調度算法。

--- 調度線程

  上面文字中提到優先級可以由操作系統動態調整。Windows 除了會在前后臺切換的時候調整優先級還會為 I/O 操作動態提升優先級,或者使用 “饑渴” 的時間片分配策略來動態調整,如果有線程一直渴望得到時間片但是很長時間都沒有獲得時間片,Windows 就會臨時將這個線程的優先級提高,并一次分配給2倍的時間片來執行,當用完2倍的時間片后,優先級又會恢復到之前的水平。

 

  線程運行狀態

 

  一個線程從開始到終止可能會有上述幾種狀態,這幾種狀態可以互相轉換。(上圖中的 “就緒” 指的是 runnable 狀態,又稱為 “ready to run” 狀態,個人感覺翻譯成 “就緒” 比 “可運行” 要來得明白)。

 

Thread.Yeild

  對上述概念有所了解后,我將正式介紹這三個方法的區別。

 

  該方法是在 .Net 4.0 中推出的新方法,它對應的底層方法是 SwitchToThread。

  Yield 的中文翻譯為 “放棄”,這里意思是主動放棄當前線程的時間片,并讓操作系統調度其它就緒態的線程使用一個時間片。但是如果調用 Yield,只是把當前線程放入到就緒隊列中,而不是阻塞隊列。如果沒有找到其它就緒態的線程,則當前線程繼續運行。

Yielding is limited to the processor that is executing the calling thread. The operating system will not switch execution to another processor, even if that processor is idle or is running a thread of lower priority. If there are no other threads that are ready to execute on the current processor, the operating system does not yield execution, and this method returns false. 

This method is equivalent to using platform invoke to call the native Win32 SwitchToThread function. You should call the Yield method instead of using platform invoke, because platform invoke bypasses any custom threading behavior the host has requested.

--- Thread.Yield Method

 

  優勢:比 Thread.Sleep(0) 速度要快,可以讓低于當前優先級的線程得以運行。可以通過返回值判斷是否成功調度了其它線程。

  劣勢:只能調度同一個處理器的線程,不能調度其它處理器的線程。當沒有其它就緒的線程,會一直占用 CPU 時間片,造成 CPU 100%占用率。

 

 

Thread.Sleep(0)

  Sleep 的意思是告訴操作系統自己要休息 n 毫秒,這段時間就讓給另一個就緒的線程吧。當 n=0 的時候,意思是要放棄自己剩下的時間片,但是仍然是就緒狀態,其實意思和 Yield 有點類似。但是 Sleep(0) 只允許那些優先級相等或更高的線程使用當前的CPU,其它線程只能等著挨餓了。如果沒有合適的線程,那當前線程會重新使用 CPU 時間片。

 

If you specify 0 milliseconds, the thread will relinquish the remainder of its time slice but remain ready.

--- Sleep Function

 

  優勢:相比 Yield,可以調度任何處理器的線程使用時間片。

  劣勢:只能調度優先級相等或更高的線程,意味著優先級低的線程很難獲得時間片,很可能永遠都調用不到。當沒有符合條件的線程,會一直占用 CPU 時間片,造成 CPU 100%占用率。

 

Thread.Sleep(1)

   該方法使用 1 作為參數,這會強制當前線程放棄剩下的時間片,并休息 1 毫秒(因為不是實時操作系統,時間無法保證精確,一般可能會滯后幾毫秒或一個時間片)。但因此的好處是,所有其它就緒狀態的線程都有機會競爭時間片,而不用在乎優先級。

  優勢:可以調度任何處理器的線程使用時間片。無論有沒有符合的線程,都會放棄 CPU 時間,因此 CPU 占用率較低。

  劣勢:相比 Thread.Sleep(0),因為至少會休息一定時間,所以速度要更慢。 

 

實驗告訴你:單一線程

  測試環境Windows 7 32位、VMWare workstation、單處理器單核芯

  開發環境:Visual Studio 2012、控制臺項目、Release 編譯后將 exe 拷貝到虛擬機后運行

 

  Thread.Yeild

static%20void%20Main()%20%20%20%20{%20%20%20%20%20%20%20%20string%20s%20=%20"";%20%20%20%20%20%20%20%20%20while%20(true)%20%20%20%20%20%20%20%20{%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20s%20=%20DateTime.Now.ToString();%20//模擬執行某個操作%20%20%20%20%20%20%20%20%20%20%20%20%20%20Thread.Yeild(0);%20%20%20%20%20%20%20%20}%20%20%20%20}%20%20%20%20%20%20%20%20

 

  執行效果 

 

  Thread.Sleep(0)

static%20void%20Main()%20%20%20%20{%20%20%20%20%20%20%20%20string%20s%20=%20"";%20%20%20%20%20%20%20%20while%20(true)%20%20%20%20%20%20%20%20{%20%20%20%20%20%20%20%20%20%20%20%20s%20=%20DateTime.Now.ToString();%20%20%20%20%20%20%20%20%20%20%20%20%20Thread.Sleep(0);%20%20%20%20%20%20%20%20}}

 

  執行效果 

 

  Thread.Sleep(1)

static%20void%20Main()%20%20%20%20{%20%20%20%20%20%20%20%20string%20s%20=%20"";%20%20%20%20%20%20%20%20while%20(true)%20%20%20%20%20%20%20%20{%20%20%20%20%20%20%20%20%20%20%20%20%20s%20=%20DateTime.Now.ToString();%20%20%20%20%20%20%20%20%20%20%20%20%20Thread.Sleep(1);%20%20%20%20%20%20%20%20}}

 

  執行效果 

 

  通過上述三個實驗,很明顯說明 Thread.Sleep(1) 對于解決資源 100% 占用是有明顯效果的。

 

實驗告訴你:多線程(同優先級)

  我的實驗方法很簡單,就是通過 while 讓該線程不斷的執行,為了讓大家一目了然兩個線程的交替,通過向控制臺輸出不同的字符串來驗證。

  while 語句執行速度相當快,所以必須所以加上一些代碼來浪費CPU時間,以免大家只能看到不斷的刷屏。

 

  輔助代碼

private%20static%20void%20WasteTime()%20%20%20%20{%20%20%20%20%20%20%20%20//%20耗時約%20200ms%20%20%20%20%20%20%20%20DateTime%20dt%20=%20DateTime.Now;%20%20%20%20%20%20%20%20string%20s%20=%20"";%20%20%20%20%20%20%20%20while%20(DateTime.Now.Subtract(dt).Milliseconds%20<=%20200)%20%20%20%20%20%20%20%20{%20%20%20%20%20%20%20%20%20%20%20%20s%20=%20DateTime.Now.ToString();%20//加上這句,防止被編譯器優化%20%20%20%20%20%20%20%20}}

 

  不使用任何方法 

  讓線程們自己爭用%20CPU%20時間。

%20%20%20%20static%20void%20Main(string[]%20args)%20%20%20%20{%20%20%20%20%20%20%20%20Thread%20t%20=%20new%20Thread(()%20=>%20%20%20%20%20%20%20%20{%20%20%20%20%20%20%20%20%20%20%20%20while%20(true)%20%20%20%20%20%20%20%20%20%20%20%20{%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20WasteTime();%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Console.WriteLine("Thread%201%20==========");%20%20%20%20%20%20%20%20%20%20%20%20}%20%20%20%20%20%20%20%20});%20%20%20%20%20%20%20%20t.IsBackground%20=%20true;%20%20%20%20%20%20%20%20Thread%20t2%20=%20new%20Thread(()%20=>%20%20%20%20%20%20%20%20{%20%20%20%20%20%20%20%20%20%20%20%20while%20(true)%20%20%20%20%20%20%20%20%20%20%20%20{%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20WasteTime();%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Console.WriteLine("Thread%202");%20%20%20%20%20%20%20%20%20%20%20%20}%20%20%20%20%20%20%20%20});%20%20%20%20%20%20%20%20t2.IsBackground%20=%20true;%20%20%20%20%20%20%20%20t2.Start();%20%20%20%20%20%20%20%20t.Start();%20%20%20%20%20%20%20%20Console.ReadKey();%20%20%20%20%20%20%20%20t.Abort();%20%20%20%20%20%20%20%20t2.Abort();%20%20%20%20%20%20%20%20Console.ReadKey();}

 

  執行效果 

 

  Thread.Yeild

  修改第一個線程的方法體,加入Thread.Yield。其余代碼不變。

Thread%20t%20=%20new%20Thread(()%20=>{%20%20%20%20%20%20%20%20while%20(true)%20%20%20%20%20%20%20%20{%20%20%20%20%20%20%20%20%20%20%20%20WasteTime();%20%20%20%20%20%20%20%20%20%20%20%20Thread.Yield();%20%20%20%20%20%20%20%20%20%20%20%20Console.WriteLine("Thread%201%20==========");%20%20%20%20%20%20%20%20}});

 

  執行效果 

 

  Thread.Sleep(0)

  仿照 Thread.Yield,只不過用 Thread.Sleep(0)替換。

 

  執行效果

 

  Thread.Sleep(1)

  仿照 Thread.Yield,用 Thread.Sleep(1)替換。

 

  執行效果

 

 

  從上面的示例看出,未使用 Thread 的這幾個方法(Yield,Sleep)的例子,兩個同等優先級的線程可以獲得差不多完全一樣的CPU時間。

  而使用了 Thread 方法的那幾個例子或多或少都讓另一個線程多獲取了些時間片,但是不同的方法執行效果差得并不多。這是因為它們所讓出的時間片往往都只是幾十毫秒的事情,這么短的時間,對于我的測試代碼來說很難順利撲捉每個瞬間。

Thread2 要得到更多的時間片

 

 

實驗告訴你:多線程(不同優先級)

  先來調整下代碼,修改 Thread 1,讓它的優先級變成 “AboveNormal”。

%20%20%20%20Thread%20t%20=%20new%20Thread(()%20=>{%20%20%20%20%20%20%20%20while%20(true)%20%20%20%20%20%20%20%20{%20%20%20%20%20%20%20%20%20%20%20%20WasteTime();%20%20%20%20%20%20%20%20%20%20%20%20%20Console.WriteLine("Thread%201%20==========");%20%20%20%20%20%20%20%20}});t.Priority%20=%20ThreadPriority.AboveNormal;%20//%20加入這句話t.IsBackground%20=%20true;

 

  不使用任何方法 

Thread%20t%20=%20new%20Thread(()%20=>{%20%20%20%20%20%20%20%20while%20(true)%20%20%20%20%20%20%20%20{%20%20%20%20%20%20%20%20%20%20%20%20WasteTime();%20%20%20%20%20%20%20%20%20%20%20%20Console.WriteLine("Thread%201%20==========");%20%20%20%20%20%20%20%20}%20%20%20%20});%20%20%20%20t.Priority%20=%20ThreadPriority.AboveNormal;%20%20%20t.IsBackground%20=%20true;%20%20%20%20%20%20Thread%20t2%20=%20new%20Thread(()%20=>%20%20%20%20{%20%20%20%20%20%20%20%20while%20(true)%20%20%20%20%20%20%20%20{%20%20%20%20%20%20%20%20%20%20%20%20WasteTime();%20%20%20%20%20%20%20%20%20%20%20%20Console.WriteLine("Thread%202");%20%20%20%20%20%20%20%20}%20%20%20%20});%20%20%20t2.IsBackground%20=%20true;

 

  執行效果 

  從實驗中可以表明,低優先級的幾乎很少有使用時間片的時候。

 

  Thread.Yeild

  修改 Thread 的方法體

Thread%20t%20=%20new%20Thread(()%20=>%20%20%20%20{%20%20%20%20%20%20%20%20while%20(true)%20%20%20%20%20%20%20%20{%20%20%20%20%20%20%20%20%20%20%20%20WasteTime();%20%20%20%20%20%20%20%20%20%20%20%20Console.WriteLine("Thread%201%20==========%20{0}",Thread.Yield());%20%20%20%20%20%20%20%20}%20%20%20%20});

 

  執行效果 

 

  使用了 Yeild 之后,很明顯低優先級的線程現在也能夠獲得CPU時間了。

 

  Thread.Sleep(0)

  修改方法體

Thread%20t%20=%20new%20Thread(()%20=>%20%20%20%20{%20%20%20%20%20%20%20%20while%20(true)%20%20%20%20%20%20%20%20{%20%20%20%20%20%20%20%20%20%20%20%20WasteTime();%20%20%20%20%20%20%20%20%20%20%20%20Console.WriteLine("Thread%201%20==========");%20%20%20%20%20%20%20%20%20%20%20%20Thread.Sleep(0);%20%20%20%20%20%20%20%20}%20%20%20%20});

 

  執行效果 

 

  有沒有發現低優先級的線程又一次被無情的拋棄了?

 

  Thread.Sleep(1)

  仿照 Sleep(0),用 Sleep(1)替換。

 

  執行效果

 

  通過上面的實驗,我想你應該已經比較清楚了在不同優先級的情況下,哪個方法更適用于去切換線程。

 

本人觀點

  有鑒于 Thread.Sleep(0) 的表現,本人認為應該無情的把它取締掉。至于是用 Thread.Yeild,還是 Thread.Sleep(n) (n>0),那就根據實際情況吧。歡迎大家補充~

 

參考資源

     Consequences of the scheduling algorithm: Sleeping doesn't always help

     SwitchToThread/Thread.Yield vs. Thread.Sleep(0) vs. Thead.Sleep(1)

 

 

  本文來源《C# 基礎回顧: Thread.Sleep(0) vs Sleep(1) vs Yeild》

 

作者:stg609本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。
上一篇:atomic integer

下一篇:QML動畫和過度

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 平江县| 丽江市| 娄烦县| 大宁县| 潼关县| 延津县| 安吉县| 唐河县| 咸宁市| 兰坪| 宜君县| 顺昌县| 柳江县| 南江县| 株洲县| 天台县| 桦甸市| 奎屯市| 醴陵市| 庆城县| 马关县| 莆田市| 工布江达县| 大冶市| 互助| 扎赉特旗| 望谟县| 黑水县| 邯郸市| 华安县| 南昌市| 来宾市| 林西县| 阳高县| 沾益县| 衡阳县| 樟树市| 德保县| 梁河县| 普兰县| 堆龙德庆县|