据我了解,方法开头的Task.Yield
将强制调用者继续,如果它没有等待该方法。同时Task.Run
和ConfigureAwait(false)
both在新的线程池线程上运行一个Task,如果它没有等待该方法,它将再次强制调用者继续。
我无法理解Task.Yield
与运行新线程池线程之间的区别,因为在它返回调用者之后,它将继续执行该方法的其余部分,这基本上是相同的。
This帖子表明,Yield
和Task.Factory.StartNew
(实际上只是Task.Run
的旧版本)可以互换使用,这对我来说似乎很困惑。
答案 0 :(得分:7)
Task.Yield
不是Task.Run
的替代品,与Task.ConfigureAwait
无关。
Task.Yield
- 生成一个在等待检查完成后完成的等待。ConfigureAwait(false)
- 从忽略捕获的SynchronizationContext
的任务中生成等待。Task.Run
- 在ThreadPool
主题上执行委托。 Task.Yield
与ConfigureAwait
的不同之处在于它本身是一个等待的,而不是另一个等待的可配置包装(即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
。它的语义不太清楚。链接的答案是代码味道。