具有Task.WhenAll()的C#异步任务不起作用 参考Async/Await - Best Practices in Asynchronous Programming

我正在尝试异步执行多个任务。然后等待所有内容,然后继续。 但是不知何故,我的所有任务都没有完成。查看我的示例代码。

//List from database
List<Promotion> promotions = _dbContext.promotions.ToList();

var promotionTasks = new List<Task>();
List<Promotion> outputPromotions = new List<Promotion>();
foreach (var promotion in promotions)
{
    var task = Task.Run(() =>
    {
        var promotionStatus = GetPromotionStatus(promotion).Result;
        var newPromotion = new Promotion
        {
            Id = promotion.Id,Name = promotion.Name,Code = promotion.Code,StatusId = promotionStatus
        };

        outputPromotions.Add(newPromotion);
    });
    promotionTasks.Add(task);
}

//await Task.WhenAll(promotionTasks);
Task.WaitAll(promotionTasks.ToArray());

//Output list
return outputPromotions;

例如 我在promotions中得到了50个值(这是原始列​​表,它来自数据库)。然后在完成所有任务后,我没有始终如一地获得outputPromotions中的所有50个值。 outputPromotions它给我的计数为49、48、50、46,而不是每次都为50。 我尝试了Task.WhenAll(promotionTasks);Task.WaitAll(promotionTasks.ToArray());的等待,但结果相同。

有人可以暗示我在这里做错了吗?

myzhan 回答:具有Task.WhenAll()的C#异步任务不起作用 参考Async/Await - Best Practices in Asynchronous Programming

List<>不是线程安全的。 Task.Run似乎也没有做任何有用的事情-它只是阻止等待其他异步方法响应。

异步等待和阻塞调用(如.Result之类的混合使用也会导致潜在的死锁

使代码始终保持异步状态

参考Async/Await - Best Practices in Asynchronous Programming

该代码可以替换为:

var tasks = promotions.Select(async promotion=>
               {
                   var status=await GetPromotionStatus(promotion);
                   return new Promotion                    
                   {
                       Id = promotion.Id,Name = promotion.Name,Code = promotion.Code,StatusId = status
                   }
               });
Promotion[] newPromotions = await Task.WhenAll(tasks);

如果要将该数组转换为列表,则可以在其上使用.ToList()List(IEnumerable) constructor,例如:

var newList = newPromotions.ToList();
,

您的任务如下:

var task = Task.Run(() =>
{
    var promotionStatus = GetPromotionStatus(promotion).Result;
    var newPromotion = new Promotion
    {
        Id = promotion.Id,StatusId = promotionStatus
    };

    outputPromotions.Add(newPromotion);
});

outputPromotions只是列表。它不是多线程安全的。因此,在尝试将新项目添加到outputPromotions时会遇到竞争状况

建议将所有这些促销活动添加到列表中之后,您的所有任务均已完成。通常,这不会成为您表现的瓶颈。

本文链接:https://www.f2er.com/3111351.html

大家都在问