异步 - 等待两个异步任务完成

3
我有两个函数调用在我的代码中运行,当两个都完成后,函数ProcessFiles被运行。就像这样:

  byte[] file1 = doSomething();
  byte[] file2 = doSomethingElse();

  ProcessFiles(file1, file2);

这两个函数调用DoSomethingDoSomethingElse是完全独立的,我正在考虑在不同的线程中运行它们以使它们同时运行。 然而,当两者都完成时,我需要处理结果(file1和file2)。
我想这里应该使用async await(或其VB.NET等效项),但是我非常困扰,找不到任何很好的展示示例。也许我使用了错误的搜索查询,但到目前为止,我还没有能够获得一个好的例子。请问有谁可以指点我一下吗?
2个回答

5

使用async/await非常容易实现此功能,例如:

// If you don't have async equivalents, you could use Task.Run
// to start the synchronous operations in separate tasks.
// An alternative would be to use Parallel.Invoke
Task<byte[]> task1 = DoSomethingAsync();
Task<byte[]> task2 = DoSomethingElseAsync();

byte[] file1 = await task1;
byte[] file2 = await task2;
ProcessFiles(file1, file2);

重要的是,在你开始任何一个任务之前,都不要等待另一个任务的开始。


谢谢你的回答。我可以这样理解,主线程会在“byte[] file1 = await task1”这一行阻塞吗?如果task2先完成,这并不重要(也就是说结果不会丢失)。 - Steven Lemmens
@StevenLemmens:是的,两个都是。如果task2先完成,那么只要task1一完成,await task2就会非常快地执行(甚至不需要调度继续执行)。 - Jon Skeet

5
我在考虑将它们放在不同的线程中运行...我猜想可以使用异步和等待。
请注意,async/await并没有暗示任何特定类型的线程。异步/等待处理异步代码,而不是并行代码。有关更多信息,请参阅我的async介绍
但是,您可以使用 Task.Run 在线程池线程上执行代码,然后您可以使用Task.WhenAll来(异步地)等待它们都完成:
var task1 = Task.Run(() => doSomething());
var task2 = Task.Run(() => doSomethingElse());

var results = await Task.WhenAll(task1, task2);
ProcessFiles(results[0], results[1]);

或者,既然你的代码已经是同步的,你可以使用WaitAll。请注意,在并行代码中,您的错误处理方式不同(您需要准备好AggregateException):

var task1 = Task.Run(() => doSomething());
var task2 = Task.Run(() => doSomethingElse());

Task.WaitAll(task1, task2);
ProcessFiles(task1.Result, task2.Result);

感谢您提供的代码示例和额外的解释。您的博客关于async/await也是一篇很棒的文章。现在有一个额外的问题:我之前没有考虑过的事情。我的doSomething()方法实际上使用了当前用户的一些数据。是否有一种自动将当前上下文传递给正在运行的任务的方法?我现在正在使用您的第二个示例。 - Steven Lemmens
@StevenLemmens:我相信你必须从工作线程特别设置线程的主体。据我所知,没有更简单的方法来流动它。 - Stephen Cleary

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接