簡體   English   中英

parallel linq:AsParallel()。forAll()使一些對象為空

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM