await Task.Yield()
的意义就是一句话:释放控制权,让其他任务得到执行的机会。
为什么要这么做呢?主要是 为了让调用者没有 await 的时候可以立即返回。
考虑以下例子:
1 | async Task Test() |
因为 Test 方法开头有一段耗时的操作,会阻塞 Foo 一秒钟。直到碰上await
释放了控制权,此时由于调用方并没有用await
去等待 Test 方法,所以 Foo 才得以继续执行。
问题是什么呢?问题在于 Foo 希望立即返回,而你(Test方法)却阻塞了我一秒钟!
作为异步 API 的设计者,那么就可以在函数开头加上一句await Task.Yield()
。
1 | async Task Test() |
这就实现了一个真正的异步方法!但注意这里有个前提,就是 调用者没有使用 await 去等待时才有意义。
为什么不用 Task.CompletedTask?
从前面的内容来看,要实现一个能立即返回的异步方法,重点就是要尽可能快的调用await
以达到释放控制权的目的。
那么我们可以去await
框架内部的一些特殊的任务,比如 Task.CompletedTask。
1 | async Task Test1() |
Task.CompletedTask
是一个已经完成的 Task 对象,它表示一个不返回任何结果的已完成任务。它会立即返回,并且不会引发线程切换。因为任务已经完成,不需要等待。
所以它和Task.Yield
不是一回事。
Task.Delay(0) 呢?
1 | async Task Test1() |
在 Task.Delay 实现中,延迟时间为 0 时将会返回Task.CompletedTask
。
参考
When would I use Task.Yield()?
C#/.NET 中 Thread.Sleep(0), Task.Delay(0), Thread.Yield(), Task.Yield() 不同的执行效果和用法建议
await Task.Yield()和await Task.CompletedTask有什么不同
终于明白了 C# 中 Task.Yield 的用途
Task.Delay(0) not asynchronous
Task.Yield() versus Task.Delay(0)