我什么时候可以使用Task.Yield()?

我使用asynchronous/等待和Task很多,但从来没有使用Task.Yield() ,说实话,即使所有的解释,我不明白为什么我会需要这种方法。

有人可以给出一个很好的例子, Yield()是必需的吗?

当你使用async / await ,不能保证你在await FooAsync()时调用的方法实际上是asynchronous运行的。 内部实现可以使用完全同步的path自由返回。

如果你正在制作一个关键的API,它不会阻塞,并且你可以asynchronous地运行一些代码,并且有可能被调用的方法将同步运行(有效地阻塞),使用await Task.Yield()会强制你的方法是asynchronous的,并在那一刻返回控制权。 剩下的代码将会在当前的上下文中执行(此时它仍然可以同步运行)。

如果你制作一个需要一些“长时间运行”初始化的asynchronous方法,这也是有用的,即:

  private async void button_Click(object sender, EventArgs e) { await Task.Yield(); // Make us async right away var data = ExecuteFooOnUIThread(); // This will run on the UI thread at some point later await UseDataAsync(data); } 

没有Task.Yield()调用,该方法将一直同步执行,直到第一个调用await

在内部,如果SynchronizationContext.Currentnull ,则await Task.Yield()只是在当前同步上下文或随机池线程上对继续进行排队。

它是自定义的服务器有效地实现 。 产生相同效果的效率较低的代码可能如此简单:

 var tcs = new TaskCompletionSource<bool>(); var sc = SynchronizationContext.Current; if (sc != null) sc.Post(_ => tcs.SetResult(true), null); else ThreadPool.QueueUserWorkItem(_ => tcs.SetResult(true)); await tcs.Task; 

Task.Yield()可以用作一些奇怪的执行stream改变的捷径。 例如:

 async Task DoDialogAsync() { var dialog = new Form(); Func<Task> showAsync = async () => { await Task.Yield(); dialog.ShowDialog(); } var dialogTask = showAsync(); await Task.Yield(); // we're on the dialog's nested message loop MessageBox.Show("The dialog is visible, click OK to close"); dialog.Close(); await dialogTask; // we're back to the main message loop } 

这就是说,我不能想到Task.Yield()不能被Task.Factory.StartNewreplace为适当的任务调度程序。

也可以看看:

  • “等待Task.Yield()”及其替代品

  • Task.Yield – 真正的用法?

我有一个基类,它有一个主要的方法:

 public async Task SendAsync (message); 

然后,我决定在以后的日子,我想审核发送的消息在基类的更高级的变体,我添加了两个基本的方法:

 protected virtual async Task OnBeforeSend(message); protected virtual async Task OnAfterSend(message); 

在我的类的专门版本中,我将实现添加到发送消息之前和之后的方法中,但不需要在发送方法之前和之后添加自定义到我的基类实现。 我要求我的基地实施也是一个具体的types,因为它正在其他地方使用。

为了保持编译器的快乐,我需要提供一个任务结果给基础(空)的实现,我为此使用了Task.Yield()方法。 因此,在我的基类实现中,我有这样的:

 protected virtual async Task OnBeforeSend(IEmailMessage mailMessage) { await Task.Yield(); } 

这似乎对我很好,我看不出这是错的。