![](/img/trans.png)
[英]Is updating a property for an object in a Parallel.ForEach thread safe?
[英]Is this use of Parallel.ForEach() thread safe?
本質上,我正在處理這個:
var data = input.AsParallel();
List<String> output = new List<String>();
Parallel.ForEach<String>(data, line => {
String outputLine = "";
// ** Do something with "line" and store result in "outputLine" **
// Additionally, there are some this.Invoke statements for updating UI
output.Add(outputLine);
});
輸入是一個List<String>
object。ForEach ForEach()
語句對每個值進行一些處理,更新 UI,並將結果添加到output
List
中。 這有什么本質上的錯誤嗎?
筆記:
更新:
根據我收到的反饋,我在output.Add
語句以及 UI 更新代碼中添加了手動lock
。
是; List<T>
不是線程安全的,因此從任意線程(很可能同時)ad-hoc添加它是注定的。 您應該使用線程安全列表,或手動添加鎖定。 或者也許有一個Parallel.ToList
。
此外,如果重要:插入訂單將無法保證。
不過這個版本是安全的:
var output = new string[data.Count];
Parallel.ForEach<String>(data, (line,state,index) =>
{
String outputLine = index.ToString();
// ** Do something with "line" and store result in "outputLine" **
// Additionally, there are some this.Invoke statements for updating UI
output[index] = outputLine;
});
這里我們使用index
來更新每個並行調用的不同數組索引。
這有什么本質上的錯誤嗎?
是的,一切。 這些都不安全。 列表並不安全地同時更新多個線程,並且您無法從UI線程以外的任何線程更新UI。
文檔說明了以下關於List<T>
的線程安全性:
此類型的公共靜態(在Visual Basic中為Shared)成員是線程安全的。 任何實例成員都不保證是線程安全的。
List(Of T)可以同時支持多個讀者,只要不修改集合即可。 枚舉通過集合本質上不是線程安全的過程。 在枚舉與一個或多個寫訪問爭用的極少數情況下,確保線程安全的唯一方法是在整個枚舉期間鎖定集合。 要允許多個線程訪問集合以進行讀寫,您必須實現自己的同步。
因此, output.Add(outputLine)
不是線程安全的,您需要自己確保線程安全,例如,通過將add操作包裝在lock
語句中。
當您想要並行操作的結果時, PLINQ比Parallel
class 更方便。您通過將input
轉換為ParallelQuery<T>
開始得很好:
ParallelQuery<string> data = input.AsParallel();
...但隨后您將data
提供給Parallel.ForEach
,它將其視為標准IEnumerable<T>
。 所以AsParallel()
被浪費了。 它不提供任何並行化,只提供開銷。 下面是使用 PLINQ 的正確方法:
List<string> output = input
.AsParallel()
.Select(line =>
{
string outputLine = "";
// ** Do something with "line" and store result in "outputLine" **
return outputLine;
})
.ToList();
您應該記住的一些差異:
Parallel
默認在ThreadPool
上運行代碼,但它是可配置的。 PLINQ 專門使用ThreadPool
。Parallel
默認情況下具有無限並行性(它使用ThreadPool
的所有可用線程)。 PLINQ 默認使用最多Environment.ProcessorCount
線程。 關於結果的順序,默認情況下 PLINQ 不保留順序。 如果您想保留訂單,您可以附加AsOrdered
運算符。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.