启动任务和等待任务有什么区别?

Jan*_*e E 2 c# asynchronous task-parallel-library async-await

开始和等待有什么区别?下面的代码取自 Stephen Cleary 的博客(包括评论)

public async Task DoOperationsConcurrentlyAsync()
{
  Task[] tasks = new Task[3];
  tasks[0] = DoOperation0Async();
  tasks[1] = DoOperation1Async();
  tasks[2] = DoOperation2Async();

  // At this point, all three tasks are running at the same time.

  // Now, we await them all.
  await Task.WhenAll(tasks);
}
Run Code Online (Sandbox Code Playgroud)

我认为任务在您等待它们时开始运行......但代码中的注释似乎暗示不然。另外,在我将任务归因于类型为 Task 的数组后,这些任务如何运行。这难道不是一种归因,本质上不涉及行动吗?

tra*_*r0x 6

ATask返回“热”(即已经开始)。await异步等待Task完成。

在您的示例中,您实际执行的操作await将影响任务是一个接一个地运行,还是同时运行所有任务:

await DoOperation0Async(); // start DoOperation0Async, wait for completion, then move on
await DoOperation1Async(); // start DoOperation1Async, wait for completion, then move on
await DoOperation2Async(); // start DoOperation2Async, wait for completion, then move on
Run Code Online (Sandbox Code Playgroud)

相对于:

tasks[0] = DoOperation0Async(); // start DoOperation0Async, move on without waiting for completion
tasks[1] = DoOperation1Async(); // start DoOperation1Async, move on without waiting for completion
tasks[2] = DoOperation2Async(); // start DoOperation2Async, move on without waiting for completion

await Task.WhenAll(tasks); // wait for all of them to complete
Run Code Online (Sandbox Code Playgroud)

更新

“在这个例子中(并且不仅如此),不await进行操作......表现得像同步?因为我们不能(!)在第一种情况下并行运行任何其他东西。相比之下,在第二种情况下和并行运行(例如并发,主要好处?)”asyncDoOperation0Async()DoOperation0Async()DoOperation1Async()async

这是一个大主题,也是一个值得提出的问题,因为它在 SO 上有自己的线程,因为它偏离了启动任务和等待任务之间差异的原始问题 - 因此我将保持这个答案简短,同时在适当的情况下向您推荐其他答案。

不,awaitingasync操作不会使其表现得像同步;这些关键字的作用是使开发人员能够编写类似于同步工作流程的异步代码(有关更多信息,请参阅 Eric Lippert 的回答)。

调用await DoOperation0Async() 不会阻塞执行此代码流的线程,而同步版本DoOperation0(或类似的DoOperation0Async.Result)将阻塞线程,直到操作完成。

在网络环境中考虑这个问题。假设请求到达服务器应用程序。作为生成对该请求的响应的一部分,您需要执行长时间运行的操作(例如,查询外部 API 以获取生成响应所需的一些值)。如果此长时间运行的操作的执行是同步的,则执行请求的线程将被阻塞,因为它必须等待长时间运行的操作完成。另一方面,如果这个长时间运行的操作的执行是异步的,则可以释放请求线程,以便它可以在长时间运行的操作仍在运行时执行其他操作(例如为其他请求提供服务)。然后,当长时间运行的操作最终完成时,请求线程(或者可能是线程池中的另一个线程)可以从它停止的地方继续(因为长时间运行的操作将完成并且其结果现在可用) )并完成剩下的工作以产生响应。

服务器应用程序示例还解决了您问题的第二部分,即async- async/的主要优点await是释放线程。