当存在参数依赖时如何使用 WhenAll()?

How to use WhenAll() when there are parameter dependencies?

提问人:gilpach 提问时间:9/7/2023 最后编辑:Theodor Zouliasgilpach 更新时间:9/7/2023 访问量:76

问:

在执行多个异步任务时,我想使用一种方法,以便获得使用它的好处:组合错误传播等。WhenAll()

鉴于以下几点:

var item1Task = _service.GetItem1(item1Id);
var item2Task = _service.GetItem2(item2Id);
var item3Task = _service.GetItem3(item3Id);

var allTasks = Task.WhenAll(item1Task, item2Task, item3Task);

try  
{
    await allTasks;
}
catch
{
  ... // some error handling
} 


return new AggregateItems() 
{
  Item1 = item1Task.Result,
  Item2 = item2Task.Result,
  Item3 = item3Task.Result,
}

如果传递给的参数来自 的属性,有没有办法仍将调用合并到方法中,或者在检索 的值后它必须存在于方法之外?item3Id_service.GetItem3(item3Id)Item1GetItem3()WhenAll()Item1

C# 异步 任务 task-parallel-library

评论

5赞 EyesShriveledToRaisins 9/7/2023
自己回答这个问题:如果尚未完成并且尚未生成 Item1,如何根据尚不存在的结果同时运行?时光机?虫 洞?;-)_service.GetItem1(item1Id)_service.GetItem3(item3Id)_service.GetItem1(item1Id)_service.GetItem1(item1Id)
2赞 Servy 9/7/2023
在当前代码中调用 实际上不执行任何操作。现有代码也会同步运行,而不是异步运行,因为您使用的是 而不是 .WhenAllResultawait
0赞 gilpach 9/7/2023
@Servy,呃,在试图简化帖子的代码时,我删除了必要的一行。无论哪种方式,我认为 EyesShriveledToRaisins 用他的问题回答了我的问题。我只是想知道是否有任何巫毒教可以做到。我意识到依赖关系强制同步流。
0赞 gilpach 9/7/2023
@EyesShriveledToRaisins,要点。

答:

1赞 Theodor Zoulias 9/7/2023 #1

async/await是可组合的。这允许您有一个方法,该方法将 a 作为参数,并在启动和等待依赖于参数结果的异步操作之前执行此任务。例:asyncTask<T>await

var item1Task = _service.GetItem1(item1Id);
var item2Task = _service.GetItem2(item2Id);
var item3Task = LocalGetItem3(item1Task);

var allTasks = Task.WhenAll(item1Task, item2Task, item3Task);

async Task<Z> LocalGetItem3(Task<X> item1Task)
{
    X item1 = await item1Task;
    return await _service.GetItem3(item1);
}

局部函数是 / 组合的一个例子。LocalGetItem3asyncawait

显然,操作和将按顺序运行,一个接一个,因为第二个取决于第一个的结果。如果失败,任务将在其 Exception 属性中包含两次相同的异常。这是因为任务和都将失败并出现相同的错误。_service.GetItem1_service.GetItem3_service.GetItem1allTasksitem1Taskitem3Task

评论

0赞 Jeroen van Langen 9/7/2023
那会是一种选择吗?.ContinueWith()
1赞 Charlieface 9/7/2023
@JeroenvanLangen 没有坏主意,最好只使用它来整理解包和正确的异常处理。await
0赞 Theodor Zoulias 9/7/2023
@JeroenvanLangen这很尴尬,因为你必须处理前期任务的所有三种可能状态。如果任务配备了 / 扩展方法,将 lambda 作为参数,其中包含先前任务的结果而不是任务本身,那就太好了。不幸的是,我们没有这种奢侈ContinueWithContinueWithResultThen