c# - 使用 Task.WhenAll 但需要跟踪每个单独任务的成功

标签 c# .net asp.net-core async-await

原始方法是等待每个作业的低效 foreach 循环(这是一个 I/O 绑定(bind)网络调用):

foreach (var job in Jobs)
{
    try
    {
        await DoJobAsync(job); //Pass job to external vendor API
        job.Succeeded = true;
    }
    
    catch (Exception)
    {
        //do nothing, let loop continue
    }
}

现在为了提高性能,我想使用 Task.WhenAll 以非阻塞方式处理所有作业。

但是,如果 DoJobAsync 任务不会抛出异常。

如果我们这样做:

await Task.WhenAll(Jobs.Select(j =>
{
    var task = DoJobAsync(j);
    j.Succeeded = true;
    return task;
}));

我的理解是,如果任何作业任务最终抛出异常,该属性仍将切换为 true,因为每个单独的任务在创建时都不会等待,从而使代码流直接过去

我知道我可以捕获 Task.WhenAll 返回的 Task 以访问抛出的所有异常的列表,但我想不出办法使用它们可以追溯到引发异常的 job

我该如何解决这个问题?

最佳答案

您可以使用异步委托(delegate)作为 Select选择器运算符(operator):

await Task.WhenAll(Jobs.Select(async job =>
{
    await DoJobAsync(job);
    job.Succeeded = true;
}));

这样每个作业都将被投影到一个 Task ,它不是原始的 DoJobAsync(job) 任务,而是一个封装更新逻辑的包装器任务Succeeded 属性。此属性将在 DoJobAsync(job) 任务成功完成后立即更新。

多个 Job 对象可能会同时更新它们的 Succeeded 属性。这取决于当前线程上是否安装了 SynchronizationContext

关于c# - 使用 Task.WhenAll 但需要跟踪每个单独任务的成功,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71259632/

相关文章:

c# - .NET Core API - 为什么嵌套模型中的文件属性接收 null?

c# - 如何在 ASP.NET Core MVC 中启用跨源请求 (CORS)

c# - 如何在 ASP.NET Core 3 上同时使用 Azure AD 身份验证和身份?

c# - Azure 服务总线属性筛选器

c# - 如何使用光子统一在固定位置生成多人游戏用户?

c# - 使用 Entity Framework 保存 AutoMapper 映射的实体集合

asp.net - 如何以编程方式将位置元素添加到 Web 配置?

c# - 如何在 LINQ 语句中使用扩展方法?

c# - Visual Studio 安装程序项目中的其他设置

c# - 是否需要自定义 Winforms 控件自动生成设计器文件?