2012-10-29 1112 views
24

的Windows 7,英特爾酷睿i3,64位,4GB內存,2.27 GHz的
的.NET Framework 4.0
爲什麼Thread和Task之間的性能差異如此之大?

我有以下代碼:

static void Main(string[] args) 
{ 
    var timer = new Stopwatch(); 
    timer.Start(); 

    for (int i = 0; i < 0xFFF; ++i) 
    { 
     // I use one of the following line at time 
     Task.Factory.StartNew(() => { }); 
     new Thread(() => { }).Start(); 
    } 

    timer.Stop(); 

    Console.WriteLine(timer.Elapsed.TotalSeconds); 
    Console.ReadLine(); 
} 

如果我使用任務的輸出總是小於0.01秒,但如果我使用線程輸出始終大於40秒
這怎麼可能?爲什麼這麼差?

+15

一開始4096個線程,其他隊列4096級的任務隊列中的..你不是衡量以外的其他任何東西。毫無意義。 –

回答

30

兩者不一樣。

當您使用Task.Factory.StartNew時,您正在計劃任務在ThreadPool上運行。當您製作新的Thread時,您必須創建並啓動一個新線程。

在第一種情況中,線程已經創建並重用。這會導致調度任務的開銷更低,因爲線程不必每次迭代都創建一次。

但請注意,行爲並不相同。當創建一個單獨的線程時,每個任務都得到它自己的線程。他們都會馬上開始。當使用Task.Factory.StartNew時,它們被放入調度程序以在ThreadPool上運行,這將(可能)限制啓動的併發線程數。這通常是一件好事,因爲它可以防止發生過度閱讀。

+0

所以,如果我使用Task,它一次可以運行指定的委託。即只有當前一個完成時,Task類纔開始下一個? – Nick

+0

[Task.ContinueWith](http://msdn.microsoft.com/en-us/library/dd235663.aspx):'var t = Task.Factory.StartNew(...)。ContinueWith(...)' 。 – user7116

+0

@Nick您可以使用延續,或者,如果您想阻止,請在Task任務'上調用'.Wait()'或'.Result'。話雖如此,如果你想按順序處理項目*,你可能想看看BlockingCollection ,然後創建一個生產者/消費者場景。 –

0

Task.Factory.StartNew()不會立即啓動任務,只是調度它,以便TaskScheduled稍後可以啓動它(取決於可用線程/任務的數量)。

MSDN說,在Thread.Start()操作系統可以調度它執行之後,與操作系統的交互比.NET框架的TaskScheduler慢得多,但是沒有這樣的程度。

回到你的例子,0xFFF == 4095,所以你正在安排4095個線程,這需要40秒。一秒鐘內有102個線程是相當不錯的時機! :)

4

每當您啓動一個Task它將進入一個池,由多個線程提供服務,其中許多線程可能是預先創建的。池中任務與線程的比率爲M:N

每次啓動一個Thread它創建一個新的線程,所有線程創建相關的開銷。由於您明確創建了一個線程,因此線程的比例爲1:1。

任務與線程的比率越接近1,將執行「較慢」的任務啓動。實際上,ThreadPool可確保比率遠遠高於1.

0

調用Task.Factory.StartNew不一定會創建新線程,它們由TaskScheduler根據機器運行代碼的核心數量來管理。

如果計劃(通過調用Task.Factory.StartNew)任務多於可同時運行,它們將排隊並運行在更多的資源可用。

1

您的測試存在問題,因爲您不必等待每個線程/任務完成。

任務使用一個隊列,所以創建任務的速度比線程快得多。

我敢打賭,即使您等待任務/線程完成,使用任務的速度也會更快。創建和銷燬線程的開銷很高。這就是爲什麼Task.Factory被創建的原因!

相關問題