【发布时间】:2019-02-20 22:19:18
【问题描述】:
我以为我理解 async/await 但显然不是。我有这样的事情:
public async void SomeEventHandler()
{
await Task.Run(() => Method1());
}
private async Task Method1()
{
// Running on a worker thread here.
await SomeOtherMethodAsync();
// Now running on the UI thread.
}
从上面的 cmets 中可以看出,Method1 一开始是在 b/g 线程上运行,正如您所期望的那样,它被使用 Task.Run() 调用。然而,在第一个await 之后,剩余的代码将在 UI 线程上运行。我相信将ConfigureAwait(false) 添加到“内部”异步方法调用将防止这种情况发生,但我不明白它首先在 UI 线程上恢复的原因。为什么是 UI 线程而不是原始(或其他)b/g 线程?
当然,“默认”在 UI 线程上恢复会适得其反,因为可能会阻塞 UI,而这正是 async/await 试图避免的。
在我的真实代码中,Method1 做了很多 CPU 密集型工作,因此我使用 Task.Run 来调用它;该方法还调用了许多异步 I/O 绑定方法。我在使用 async/await 和 Task.Run 时采取了正确的方法吗?
编辑 澄清一下,我在 Method1 和 Threads 窗口中使用了断点来查看代码在哪个线程上运行。在可等待方法调用之前,线程窗口突出显示了一个工作线程,而在可等待方法调用之后,“主线程”被突出显示。
编辑2 回应@Aly 下面的回答,使用相同的调试文本,这就是我所看到的:
ManagedThreadID (Dispatcher): 11
ManagedThreadID (MainThread - before Task.Run(Method1)): 11
ManagedThreadID (Method1 - before SomeOtherMethodAsync): 14
ManagedThreadID (SomeOtherMethodAsync): 14
ManagedThreadID (Method1 - after SomeOtherMethodAsync): 11
ManagedThreadID (MainThread - after Task.Run(Method1)): 18
【问题讨论】:
-
"现在在 UI 线程上运行。" ——不,不是。不可能。上面一行中的
await没有 SynchronizationContext 来捕获。我刚刚在 WPF 应用程序中尝试过并确认了它。 -
@PanagiotisKanavos 不,这是不会发生的行为。有问题的
await没有要恢复的原始同步上下文。SomeEventHandler中await之后的代码是另一回事,但这不是他要问的问题。请先尝试有问题的代码,然后再说出它执行 OP 所说的操作! -
@PanagiotisKanavos 他说“方法 1 开始于您所期望的 b/g 线程上运行,已使用 Task.Run() 调用。但是在第一次等待之后,其余代码然后运行UI线程”这是相当明确的IMO。你说这是预期的行为,这是错误的。这得到了他示例中的代码 cmets 的支持。
-
@AndrewStephens 我认为你已经把你的问题简化得太多了,你最终得到的东西并不能证明你的问题。您断言代码处的注释“// 现在在 UI 线程上运行”。在 UI 线程上运行是不正确的,您可以通过一个简单的测试应用程序看到这一点。请使用实际重现您的问题的示例更新您的问题。
-
@AndrewStephens 对,所以问题出在我们看不到的代码中,您不会与我们分享。输出没有任何意义,因为它是某个包含问题的黑匣子的输出,但我们无法检查。如果您在您的问题 中发布了示例代码的输出,那将是不同的。但是,就目前而言,示例代码仍然无用,因为它没有说明问题。
标签: c# wpf asynchronous async-await