从连续的异步方法中获取任务(非并行)
Get a Task out of consecutive async methods (not in parallel)
关于如何在特定情况下使用 await/async 模式,我还有一个问题。
假设我在一个在项目集合上循环的方法中,我想并行执行一些事情。因此,我创建了一个 List<Task>
并且对于循环的每次迭代,我在后台开始一些工作并将其 Task
添加到该列表中。在该方法的最后,我将在该列表上调用 Task.WhenAll
。
现在,假设在我的循环中,我有两个不能并行执行的异步方法,也就是说,第二个需要在第一个完成后调用。
没有优化,代码看起来像这样:
// Lets assume I have an items list inside each loop iteration
await FirstMethodAsync(items);
await items.SecondMethodAsync(item => item.SomeProperty);
现在,由于循环可以在调用这两个方法时继续进行,因此这种方法确实效率低下。
注意:我希望 main 方法保持 运行ning 而这两个链式异步方法 运行 在后台。
第二种方法:我已经准备好 List<Task>
并且在循环的每次迭代中添加一个新任务。问题是,第二种方法必须在第一种方法 之后 被调用。到目前为止,这是我的解决方案:
// Let's assume my List<Task> is simply called tasks
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
FirstMethodAsync(items).ContinueWith(t1 => items.SecondMethodAsync(item => item.SomeProperty).ContinueWith(t2 => tcs.SetResult(null)));
tasks.Add(tcs.Result);
// Later on, at the end of the loop and right before the method returns
await Task.WhenAll(tasks);
这有效,一旦我调用第一个线程,控制 returns 就进入循环迭代,这是我想要实现的。所以,我去掉了两个 await
运算符,整个解决方案似乎没问题。
我只是不确定这是最好的方法:必须创建一个 TaskCompletionSource
并调用这两个嵌套的 ContinueWith
方法会使代码看起来很糟糕,而且确实有更好的方法这样做的方法。
最好的(例如,最干净、最有可能是正确的,以及最容易维护) 解决方案是使用单独的方法:
for (...)
{
tasks.Add(BothMethodsAsync(items));
}
await Task.WhenAll(tasks);
async Task BothMethodsAsync(... items)
{
await FirstMethodAsync(items);
await items.SecondMethodAsync(item => item.SomeProperty);
}
关于如何在特定情况下使用 await/async 模式,我还有一个问题。
假设我在一个在项目集合上循环的方法中,我想并行执行一些事情。因此,我创建了一个 List<Task>
并且对于循环的每次迭代,我在后台开始一些工作并将其 Task
添加到该列表中。在该方法的最后,我将在该列表上调用 Task.WhenAll
。
现在,假设在我的循环中,我有两个不能并行执行的异步方法,也就是说,第二个需要在第一个完成后调用。
没有优化,代码看起来像这样:
// Lets assume I have an items list inside each loop iteration
await FirstMethodAsync(items);
await items.SecondMethodAsync(item => item.SomeProperty);
现在,由于循环可以在调用这两个方法时继续进行,因此这种方法确实效率低下。 注意:我希望 main 方法保持 运行ning 而这两个链式异步方法 运行 在后台。
第二种方法:我已经准备好 List<Task>
并且在循环的每次迭代中添加一个新任务。问题是,第二种方法必须在第一种方法 之后 被调用。到目前为止,这是我的解决方案:
// Let's assume my List<Task> is simply called tasks
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
FirstMethodAsync(items).ContinueWith(t1 => items.SecondMethodAsync(item => item.SomeProperty).ContinueWith(t2 => tcs.SetResult(null)));
tasks.Add(tcs.Result);
// Later on, at the end of the loop and right before the method returns
await Task.WhenAll(tasks);
这有效,一旦我调用第一个线程,控制 returns 就进入循环迭代,这是我想要实现的。所以,我去掉了两个 await
运算符,整个解决方案似乎没问题。
我只是不确定这是最好的方法:必须创建一个 TaskCompletionSource
并调用这两个嵌套的 ContinueWith
方法会使代码看起来很糟糕,而且确实有更好的方法这样做的方法。
最好的(例如,最干净、最有可能是正确的,以及最容易维护) 解决方案是使用单独的方法:
for (...)
{
tasks.Add(BothMethodsAsync(items));
}
await Task.WhenAll(tasks);
async Task BothMethodsAsync(... items)
{
await FirstMethodAsync(items);
await items.SecondMethodAsync(item => item.SomeProperty);
}