標籤:time cpu private write 理解 特點 就是 作業系統 空間
建議75:警惕線程不會立即啟動
現代的大多數作業系統都不是一個即時的作業系統,Windows系統也是如此。所以,不能奢望我們的線程能夠立即啟動。Windows內部會實現特殊的演算法以進行線程之間的調度,在某個具體的時刻,它會決定當前應該運行哪個線程。這反映到最底層就是某個線程分配到了一定的CPU時間,可用來執行一小段工作(由於被分配的CPU時間很短,所以即使作業系統中運行了上千個線程,我們也會覺得這些應用程式是在同時執行的)。Windows會選擇在適當的時間根據自己的演算法決定下一段的CPU時間如何調度。
線程的調度是一個複雜的過程,對於C#開發人員來說,需要理解的就是:線程之間的調度佔有一定的時間和空間開銷,並且,它不即時。下面是一個測試的例子,本意是將0到9分別傳給10個不同的線程,結果卻事與願違:
static int _id = 0; static void Main() { for (int i = 0; i < 10; i++, _id++) { Thread t = new Thread(() => { Console.WriteLine(string.Format("{0}:{1}", Thread.CurrentThread.Name, _id)); }); t.Name = string.Format("Thread{0}", i); t.IsBackground = true; t.Start(); } Console.ReadLine(); }
以上代碼的可能輸出為:
Thread0:2
Thread4:5
Thread2:3
Thread1:3
Thread5:5
Thread6:6
Thread7:7
Thread8:9
Thread3:3
Thread9:10
這段代碼的輸出從兩個方面印證了線程不是立即啟動的。
首先,我們看到線程並沒有按照順序啟動。在代碼邏輯中,前面Start的那個線程也許遲於後Start的那個線程執行。
其次,傳入線程內部的ID值,不再是for迴圈執行中當前的ID值。以Thread9為例,在for迴圈中,其當前的值為9,而Thread9真正得到執行的時候,ID卻已經跳出迴圈,早已經變為10了。
要讓需求得到正確的編碼,需要把上面的for迴圈修改成為一段同步代碼:
static int _id = 0; static void Main() { for (int i = 0; i < 10; i++, _id++) { NewMethod1(i, _id); } Console.ReadLine(); } private static void NewMethod1(int i, int realTimeID) { Thread t = new Thread(() => { Console.WriteLine(string.Format("{0}:{1}", Thread.CurrentThread.Name, realTimeID)); }); t.Name = string.Format("Thread{0}", i); t.IsBackground = true; t.Start(); } }
以上代碼輸出:
Thread0:0
Thread3:3
Thread1:1
Thread2:2
Thread5:5
Thread4:4
Thread6:6
Thread7:7
Thread8:8
Thread9:9
可以看到,線程雖然保持了不會立即啟動的特點,但是傳入線程的ID值,由於在for迴圈內部變成了同步代碼,所以能夠正確傳入。
轉自:《編寫高品質代碼改善C#程式的157個建議》陸敏技
【轉】編寫高品質代碼改善C#程式的157個建議——建議75:警惕線程不會立即啟動