【问题标题】:Is calling Task.Wait() immediately after an asynchronous operation equivalent to running the same operation synchronously?在异步操作之后立即调用 Task.Wait() 是否等同于同步运行相同的操作?
【发布时间】:2015-07-14 23:32:07
【问题描述】:

换句话说,是

var task = SomeLongRunningOperationAsync();
task.Wait();

功能与

相同
SomeLongRunningOperation();

换一种说法,就是

var task = SomeOtherLongRunningOperationAsync();
var result = task.Result;

功能相同

var result = SomeOtherLongRunningOperation();

根据Task.Wait and Inlining,如果Wait'd on的Task已经开始执行,Wait必须阻塞。但是,如果它还没有开始执行,Wait 可能能够将目标任务从其排队的调度程序中拉出并在当前线程上内联执行。

这两种情况是否仅仅是决定任务将在哪个线程上运行的问题,如果你仍然在等待结果,这有关系吗?

如果在异步调用和Wait() 之间没有执行任何操作,那么使用异步表单比同步表单有什么好处吗?

【问题讨论】:

  • 由于 SomeLongRunningOperation 返回了一些结果,我假设你的意思是var result = task.Result
  • Task.Result 是一个阻塞操作。无需Wait()
  • 是的。那么为什么要Wait()呢?
  • 你说吧。没必要。 var result = Task.Result; 就够了。
  • 罗伯特,你 Wait 一个任务,如果它没有返回任何东西。

标签: c# asynchronous task


【解决方案1】:

这里有一些区别:

  1. 计算可能在不同的线程上运行。如果此任务基于 CPU 并且可以内联,它可能会在同一线程上运行。这是不确定的。
  2. 如果没有发生内联,计算期间将使用另外一个线程。这通常需要 1MB 的堆栈内存。
  3. 异常将被包装在AggregateException 中。异常堆栈会有所不同。
  4. The task version might deadlock if the computation posts to the current synchronization context.
  5. 如果线程池已用完,如果必须安排任务完成另一个任务,这可能会死锁。
  6. 线程本地状态,例如HttpContext.Current(实际上不是线程本地但几乎是),可能不同。
  7. 主线程的线程中止不会到达任务主体(内联的情况除外)。我不确定等待本身是否会中止。
  8. 创建Task 会导致内存屏障产生同步效果。

这有关系吗?根据此列表自行决定。

这样做有什么好处吗?我什么都想不出来。如果您的计算使用异步 IO,则等待将抵消异步 IO 带来的好处。一个例外是扇出 IO,例如并行发出 10 个 HTTP 请求并等待它们。这样一来,您就可以以一个线程为代价进行 10 次操作。

请注意,WaitResult 在所有这些方面都是等效的。

【讨论】:

  • 听起来风险不超过收益(如果有的话。你没有提到任何收益)。
  • 您期望得到什么好处?我不知道,除非您明确想要列出的任何行为。
  • 我在一些我没有编写的代码中发现了这一点,并认为一定有某种原因是这样的。但是我发现代码周围没有任何东西表明它需要任何这些行为。
  • 等待和结果是等价的。如果没有可用的同步版本,这是一个很好的理由,假设他出于某种原因确实想要具有同步操作模式(也许他正在实现一个接口)。不过,在典型的 ASP.NET 代码中,这种阻塞很容易出现死锁。
  • @TheodorZoulias 我编辑了这篇文章。确实存在语言错误。感谢您指出。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-26
  • 2019-05-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多