问题 在等效于同步运行相同操作的异步操作之后立即调用Task.Wait()吗?


换句话说,是

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

功能相同的

SomeLongRunningOperation();

换句话说,是

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

功能相同的

var result = SomeOtherLongRunningOperation();

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

这两个案例只是决定任务将在哪个线程上运行,如果你还在等待结果,那有关系吗?

如果在异步调用和。之间没有执行任何操作,那么在同步表单上使用异步表单是否有任何好处 Wait()


12305
2017-07-14 23:32


起源

由于SomeLongRunningOperation返回一些结果,我认为你的意思 var result = task.Result - EZI
恩,那就对了。 - Robert Harvey♦
Task.Result是一个阻塞操作。无需 Wait() - EZI
真正。所以为什么 Wait() 在所有? - Robert Harvey♦
罗伯特,你 Wait 一个任务,如果它没有返回任何东西。 - EZI


答案:


以下是一些差异:

  1. 计算可能在不同的线程上运行。如果此任务基于CPU并且可以内联,则它可能在同一线程上运行。这是不确定的。
  2. 如果没有内联发生,则在计算过程中将使用另一个线程。这通常需要1MB的堆栈内存。
  3. 例外将包含在内 AggregateException。异常堆栈将有所不同。
  4. 如果计算发布到当前同步上下文,则任务版本可能会死锁。
  5. 如果线程池最大化,则如果必须安排完成另一个任务的任务,则可能会死锁。
  6. 线程局部状态,如 HttpContext.Current (实际上并不是线程本地的,但差不多), 威力 与众不同。
  7. 主线程的线程中止将不会到达任务主体(除了内联)。我不确定等待本身是否会中止。
  8. 创建一个 Task 诱导记忆障碍为什么可以产生同步效应。

这有关系吗?通过此列表确定您自己。

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

注意 Wait 和 Result 在所有这些方面都是等同的。


9
2017-07-14 23:52



听起来风险不超过收益(如果有的话。你没有提到任何好处)。 - Robert Harvey♦
你期望有什么好处?除非您明确要求列出任何行为,否则我不知道。 - usr
我在一些我没写过的代码中发现了这一点,并且认为必须有这样的原因。但是我发现的代码周围没有任何东西表明它需要任何这些行为。 - Robert Harvey♦
是的,可能是线程本地状态或使用STA线程的自定义调度程序或其他一些深奥的原因。通常,这应该被评论有理由,因为它是一种气味。 - usr
等待和结果是等效的。如果没有可用的同步版本,这是一个很好的理由,假设他真的想要出于某种原因(可能是他正在实现一个接口)的同步操作模式。但是,在典型的ASP.NET代码中,这种阻塞很容易出现死锁。 - usr