Task.Yield,Task.Run和ConfigureAwait(false)之间有什么区别?

时间:2015-07-04 15:00:28

标签: c# multithreading asynchronous async-await task

据我了解,方法开头的Task.Yield将强制调用者继续,如果它没有等待该方法。同时Task.RunConfigureAwait(false) both在新的线程池线程上运行一个Task,如果它没有等待该方法,它将再次强制调用者继续。

我无法理解Task.Yield与运行新线程池线程之间的区别,因为在它返回调用者之后,它将继续执行该方法的其余部分,这基本上是相同的。

This帖子表明,YieldTask.Factory.StartNew(实际上只是Task.Run的旧版本)可以互换使用,这对我来说似乎很困惑。

2 个答案:

答案 0 :(得分:7)

Task.Yield不是Task.Run的替代品,与Task.ConfigureAwait 无关。

  • Task.Yield - 生成一个在等待检查完成后完成的等待。
  • ConfigureAwait(false) - 从忽略捕获的SynchronizationContext的任务中生成等待。
  • Task.Run - 在ThreadPool主题上执行委托。

Task.YieldConfigureAwait的不同之处在于它本身是一个等待的,而不是另一个等待的可配置包装(即Task)。另一个区别是Task.Yield会在捕获的上下文中继续。

Task.Run不同,因为它只需要一个代理并在ThreadPool上运行,您可以将其与ConfigureAwait(false)一起使用或不使用。

Task.Yield应该用于强制异步点,而不是Task.Run的替代。当在异步方法中达到await时,它会检查任务(或其他等待的)是否已经完成,如果是,它将继续同步。 Task.Yield可以防止这种情况发生,因此对测试非常有用。

另一种用法是在UI方法中,您不希望占用单个UI线程,插入异步点,其余的计划在以后执行。

答案 1 :(得分:5)

Task.Yield继续当前同步上下文或当前TaskScheduler(如果存在)。 Task.Run不这样做。它总是使用线程池。

例如Task.Yield将保留在UI线程上。

避免使用Task.Yield。它的语义不太清楚。链接的答案是代码味道。