[英]parallel linq: AsParallel().forAll() nulls some objects
所以,我有一個非常奇怪的情況,似乎forAll()plinq查詢刪除了我的一些自定義對象,說實話,我不知道為什么。
var myArticles = data.FilterCustomerArticles([]params]).ToList(); //always returns 201 articles
result.Articles = new List<ArticleMinimal>();
try
{
myArticles.AsParallel().ForAll(article =>
{
result.Articles.Add(new ArticleMinimal()
{
ArticleNumber = article.ArticleNumber,
Description = article.Description,
IsMaterial = false,
Price = article.PortionPrice.HasValue ? article.PortionPrice.Value : decimal.Zero,
Quantity = 1,
ValidFrom = new DateTime(1900, 1, 1),
ValidTo = new DateTime(2222, 1, 1)
});
});
}
catch (Exception ex)
{
...
}
幾乎每次調用時,上面的代碼都會返回不同的結果計數。 它應該返回201個ArticleMinimal
-Objects。 相反,它返回200,189,19x ......但不時地返回201。 沒有異常,沒有。 它只返回少於它應該的對象。
在將代碼更改為“good ol”“優雅的foreach-loop之后,我總是得到預期的201個對象。
工作守則:
var myArticles = data.FilterCustomerArticles([]params]).ToList(); //always returns 201 articles
result.Articles = new List<ArticleMinimal>();
try
{
foreach (var article in myArticles) {
result.Articles.Add(new ArticleMinimal()
{
ArticleNumber = article.ArticleNumber,
Description = article.Description,
IsMaterial = false,
Price = article.PortionPrice.HasValue ? article.PortionPrice.Value : decimal.Zero,
Quantity = 1,
ValidFrom = new DateTime(1900, 1, 1),
ValidTo = new DateTime(2222, 1, 1)
});
}
}
catch (Exception ex)
{
...
}
此外,在更多代碼行之后,我還有另外forAll
像這樣:
try
{
result.Articles.AsParallel().ForAll(article =>
{
if (article.Weight != null){
...
}
});
}
catch (Exception)
{
...
}
使用第一個forAll
,這會拋出一個NullReferenceException
- imho,因為它需要一些201個對象,但是一些Listentries是null。
現在我的實際問題是:為什么第一個forAll
返回的對象少於它應該的數量?! 我能想到的唯一線索是new ArticleMinimal(){ ...});
的內聯聲明new ArticleMinimal(){ ...});
- 但即使這是因為它對我來說似乎很奇怪。 使用plinq時是不是可以這樣做? 我只是在這里猜測。
希望你能幫忙。
最好的問候,Dom
你不能操縱結果result.Articles
來自許多線程的文章可能會破壞內部,正如你所觀察到的那樣。
而是將並行工作流轉換為返回創建對象的管道:
result.Articles.AddRange(myArticles.AsParallel().Select(article =>
new ArticleMinimal()
{
ArticleNumber = article.ArticleNumber,
Description = article.Description,
IsMaterial = false,
Price = article.PortionPrice.HasValue ? article.PortionPrice.Value : decimal.Zero,
Quantity = 1,
ValidFrom = new DateTime(1900, 1, 1),
ValidTo = new DateTime(2222, 1, 1)
})
);
的.Select
這里,因為它是被上執行ParallelQuery
由歸國.AsParallel()
將在項目並行運行。
然而.AddRange
將要求ParallelQuery.GetEnumerator()
,它將收集的項目返回到一個長集合中,為您提供所需的內容。
根本區別在於.AddRange()
可能不會添加任何內容,直到所有並行任務開始完成,而您的方式,如果添加適當的鎖定,將在生成時將項添加到集合中。 但是,除非您想要觀察在生產過程中流入集合的物品,否則在您的情況下這不太重要。
List.Add
不是線程安全的。 請參閱https://stackoverflow.com/a/8796528/98491
使用任一鎖
lock (result.Articles)
{
result.Articles.Add(...);
}
或線程安全集合。 我會使用臨時集合,最后使用result.Articles.AddRange(...)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.