2012-08-16 29 views
1

我剛剛開始瞭解一些新的.NET併發集合,如ConcurrentDictionary和ConcurrentQueue,我正在運行一些測試以查看當我寫入並行隊列時會發生什麼。隊列<T>併發給不同的結果不同的類型

於是我就這樣:

private static void ParallelWriteToQueue(Queue<int> queue) 
    { 
     Stopwatch sw = Stopwatch.StartNew(); 
     Parallel.For(1,1000001,(i) => queue.Enqueue(i)); 
     sw.Stop(); 
     Console.WriteLine("Regular int Queue - " + queue.Count + " time" + sw.ElapsedMilliseconds); 
    } 

而且因爲我認爲我得到了一個異常:

Source array was not long enough. Check srcIndex and length, and the array's lower bounds. 

所以當預測到這一隊列無法處理的併發連接隊列。

,當我改變了隊列字符串類型,沒有例外,並將結果寫入類似

Regular string Queue - 663209 time117 

這意味着只有約663k被入隊。

爲什麼沒有例外?

所有未入場的物品發生了什麼變化?

這是隊列

private static void ParallelWriteToQueue(Queue<string> queue) 
    { 
     Stopwatch sw = Stopwatch.StartNew(); 
     Parallel.For(1, 100001, (i) => queue.Enqueue(i.ToString())); 
     sw.Stop(); 
     Console.WriteLine("Regular string Queue - " + queue.Count + " time" + +sw.ElapsedMilliseconds); 
    } 
+0

您只運行第二個並行for循環到100001而不是1000001. – 2012-08-16 06:24:10

+0

@DanielHilgarth對不起,我在複製之前更改了它...它運行的迭代次數相同 – Mithir 2012-08-16 06:34:24

+2

未定義的行爲未定義。有時你遇到了錯誤,有時候你不會。 – CodesInChaos 2012-08-16 06:37:03

回答

2

是否發生異常與放入隊列中的類型無關。這是非確定性的,我可以重現這兩種類型的例外情況,我可以毫無例外地重現這兩種情況 - 無需更改代碼。

運行下面的代碼片段顯示了這一點:

int exceptions = 0; 
int noExceptions = 0; 
for (int x = 0; x < 100; ++x) 
{ 
    Queue<int> q = new Queue<int>(); 
    try 
    { 
     Parallel.For(1,1000001,(i) => q.Enqueue(i)); 
     ++noExceptions; 
    } 
    catch 
    { 
     ++exceptions; 
    } 
} 

Console.WriteLine("Runs with exception: {0}. Runs without: {1}", exceptions, noExceptions); 

的輸出是一樣的東西Runs with exception: 96. Runs without: 4

的原因是 - 因爲別人已經提到的 - 這Queue不是線程安全的。這裏發生的事情叫做"Race condition"

+0

我自己嘗試過這個功能,但是沒有發現異常,爲什麼? – Mithir 2012-08-16 06:55:16

+0

嘗試將外圈數從100增加到1000。由於這是未定義的行爲,因此不確定,因此可能有多種原因。也許你的電腦太快,太慢,內存太多或太少。真的不知道... – 2012-08-16 06:56:42

+0

對不起,我會改寫...異常被拋出,但沒有被捕獲...即執行被暫停,我得到了異常的小窗口是由用戶代碼未處理... – Mithir 2012-08-16 06:59:03

1

同樣的功能由於使用Parallel.For(),收藏一定要線程安全提供正常的工作。

所以,考慮使用ConcurrentQueue<T>類。

+0

我的問題不是關於那個,它是關於爲什麼它給不同類型的不同結果 – Mithir 2012-08-16 06:35:49

+0

@Mithir,因爲實現不是線程安全的。它沒有保證! – 2012-08-16 06:44:53

4

Queue<T>而不是ConcurrentQueue<T>不是線程安全的,按照MSDN。您所描述的其他行爲偶然發生於併發(多線程)寫入訪問中的衝突,純粹基於事實Queue<T>不是線程安全的。

2

標準集合實現不是線程安全的,您的測試顯示。使用整數引發異常但不是字符串的事實可能只是偶然,如果再次嘗試測試,您可能會得到不同的結果。

就「丟失」項目而言,無法確定 - 由於多線程訪問,隊列的內部狀態可能會損壞,因此計數本身可能是錯誤的,或者項目可能根本就不是入隊。

相關問題