2012-09-20 41 views
2

我試圖通過讓一個線程寫入鏈接列表和另一個線程處理鏈接列表來加快速度。在.net中將線程優先級從低到高更改爲:

由於某種原因,如果寫入鏈接列表的方法將其設置爲一個任務,並且從鏈接列表中讀取一個低優先級的線程的方法,程序會以更快的速度完成。換句話說,我experiense fastests結果時做:

Task.Factory.StartNew(AddItems); 

new Thread(startProcessingItems) { Priority = ThreadPriority.Lowest }.Start(); 

while(completed==false) 
    Thread.Sleep(0); 

也許是因爲第一個任務是做的比其他線程,這就是爲什麼一切作爲一個整體將更快地完成,如果我設定的第二種方法低優先級這麼多的工作。

反正現在我的問題是startProcessingItems使用ThreadPriority =最低運行。我怎麼能改變它的優先級最高?如果我在該方法中創建新的任務,它將以低優先級運行嗎?基本上startProcessingItems以列表結束,一旦它有了這個列表,我想開始以最高優先級執行。

回答

5

這不是一個好方法。首先,LinkedList<T>不是線程安全的,因此寫入並在兩個線程中讀取它將導致競爭條件。

更好的方法是使用BlockingCollection<T>。這允許您添加項目(生產者線程)和讀取項目(消費者線程),而不必擔心線程安全性,因爲它完全是線程安全的。

讀線程可以在foreach中調用blockingCollection.GetConsumingEnumerable()來獲取元素,寫線程只是添加它們。讀線程將自動阻止阻止,所以不需要混淆優先級。

當寫入線程「完成」時,您只需調用CompleteAdding,這將使讀取線程自動完成。

+0

我有一個名爲listLock的鎖,每當我添加或刪除一個使用鎖的項目時。但我想我會使用blockingCollection來代替。 +1謝謝 –

+1

@TonoNam Locking可以解決比賽條件問題,但BC會更好。它也可能會表現得更好,因爲在大多數情況下新的Concurrent集合比鎖定正常集合要好得多。 –

+0

非常感謝。我從這裏學到的東西比任何其他地方都要多。 –

2

通過改變固有設計,而不是通過更改線程/進程優先級,可以提高程序的性能。

你的問題的很大一部分是你正在做一個busywait:

while(completed==false) 
    Thread.Sleep(0); 

這導致它消耗大量的CPU週期爲沒有生產工作,這也是爲什麼降低它的優先級使它執行更快。如果你沒有等待,那麼這將不再是一個問題。

正如裏德所說,BlockingCollection是爲這種情況量身定做的。您可以讓生產者線程使用Add添加項目,使用Take的消費者線程知道如果沒有更多項目需要移除,該方法將簡單地阻止。

您還可以存儲您創建的Task,並使用Task.ResultTask.Wait讓主線程等待另一個任務完成(不浪費CPU週期)。 (如果你正在使用線程直接就可以使用Join。)

+0

非常感謝。我將使用信號量來代替。但有時在一個線程中,我不得不等待更多的項目在列表中。我使用相同的方法等到'item.Next!= null'應該同步線程嗎?如果是的話我怎麼能這樣做?我有一個線程寫入鏈接列表,另一個線程正在讀取並處理項目。 –

+1

@TonoNam由於裏德和我都說過,你應該使用'BlockingCollection'。當你使用'Take'時,它會自動等待,直到有一個項目被移除,並且它將確保所有的方法看起來都是原子的。 – Servy

2

除了什麼裏德和Servy說:

線程優先級相對於進程的優先級。

Windows調度程序在爲線程調度時間時會考慮所有其他線程。具有更高優先級的線程需要時間遠離其他線程,這可能會人爲拖慢系統的其餘部分。這不像系統沒有理由不給你線程更多的優先權。如果別的東西使CPU遠離它,優先級只會產生影響 - 這是出於某種原因。如果沒有任何東西將CPU從線程中分離出來,那麼優先級最高的時候它不會神奇地運行得更快。

將線程優先級設置爲Highest幾乎總是錯誤的做法。

可能兩個線程之間的同步開銷將會消除您認爲可能會獲得的任何性能增益。

此外,Thread.Sleep(0)只會放棄時間給同等優先級的線程,並準備運行 - 這可能會導致線程匱乏。 http://msdn.microsoft.com/en-us/library/d00bd51t(v=vs.80).aspx