Task.Yield
不是Task.Run
的替代品,也与Task.ConfigureAwait
无关。
Task.Yield
- 生成一个可等待对象,在检查完成后立即完成。ConfigureAwait(false)
- 从一个任务生成一个可等待对象,忽略了捕获的同步上下文。Task.Run
- 在ThreadPool
线程上执行委托。Task.Yield
与ConfigureAwait
的不同之处在于它本身就是一个可等待对象,而不是另一个可等待对象(即Task
)的可配置包装器。另一个区别是Task.Yield
确实在捕获的上下文中继续执行。
Task.Run
与两者都不同,因为它只需要一个委托并在ThreadPool
上运行它,你可以使用或不使用ConfigureAwait(false)
。
Task.Yield
应该用于强制执行异步点,而不是替换Task.Run
。当到达异步方法中的await时,它会检查任务(或其他可等待对象)是否已经完成,如果已经完成,则继续以同步方式执行。Task.Yield
可以防止这种情况发生,因此它在测试中很有用。
另一个用途是在UI方法中,在这些方法中,您不希望独占单个UI线程,您需要插入异步点,其余操作将在稍后执行。
Task.Yield
无法解决UI限制问题,因为UI消息队列是有优先级的(继续执行总是优于WM_PAINT
)。 - Stephen Clearyawait
将把方法继续发布到当前的SynchronizationContext
实例,该实例在内部使用BeginInvoke
(或等效)来执行。 - Stephen ClearyTask.Yield
会在当前同步上下文或当前的TaskScheduler
上继续执行,如果有的话。而Task.Run
则不会这样做,它总是使用线程池。
例如,Task.Yield
将保持在UI线程上。
避免使用Task.Yield
,其语义不够清晰。链接的答案是一种代码异味。
Task.Yield
使用 TaskScheduler.Current
的一个好处是,这是 TPL 团队另一个值得怀疑的设计决策。这个决策不能通过 .NET 4.0 兼容性原因来证明,因为在 .NET 4.0 中没有 Task.Yield
。 - noseratio - open to workTask.Yield
的行为。但是在没有同步上下文的情况下,我对使用TaskScheduler.Current
与TaskScheduler.Default
进行了质疑。我坚信应该使用后者,就像Task.Run
一样。 - noseratio - open to workawait
在当前TS上恢复,使用Task.Yield
也不应该有任何不同。Task.Run
与Task.Yield
无关,它明确地在不同的TS上执行代码。 - i3arnonTaskScheduler.Current
来进行await
是一个不好的决定。这是一个非常不直观和微妙的行为。Toub在这里提供了一个很好的例子,展示了它可能出错的情况:http://blogs.msdn.com/b/pfxteam/archive/2012/09/22/new-taskcreationoptions-and-taskcontinuationoptions-in-net-4-5.aspx。 - noseratio - open to work
Task.Run
是Task.Factory.StartNew
的一种特例,它使用默认任务调度程序(线程池任务调度程序)执行。而Task.Factory.StartNew
如果没有指定任务调度程序,则会选择当前任务调度程序,但这可能不是默认的调度程序。例如,它可能是 UI 任务调度程序。Task.Run
总是在线程池中执行。因此,Task.Run
是Task.Factory.StartNew
的一种特殊情况,不是其新版本。 - Thanasis Ioannidis