c# - 在 CPU 绑定(bind)任务上使用 await 关键字与 Task.Wait() 方法有什么区别?

标签 c# .net asynchronous async-await task-parallel-library

两者之间的机械区别是什么?

async void LongIOBoundWorkWithSomeCPUBoundWorkAsWellAsync()
{
    await Task.Run(CPUBoundWork);

    // Do IO bound work
    await DoIOAsync();
}

and

async void LongIOBoundWorkWithSomeCPUBoundWorkAsWellAsync()
{
    var cpuTask = Task.Run(CPUBoundWork);

    cpuTask.Wait();

    // Do IO bound work
    await DoIOAsync();
}

我理解,从逻辑上讲,两者都会导致相同的控制流。在这两种情况下,只有在 CPUBoundWork 任务完成执行后,才会调用 DoIOAsync 方法。

但是,在这两种情况下,CPU 任务的调度会有所不同吗?

更新

请确认我对上述代码的未受过教育的反射(reflection)是否正确。

据我了解,await 取消了线程与线程上正在运行的任务之间的任何关联。虽然这对 I/O 请求非常有用,但由于您现在重新使用在网络驱动程序上阻塞的 I/O 线程,您希望为 CPU 绑定(bind)工作保持线程亲和性。 p>

虽然 await 破坏了这种亲和性,但我不确定但纯粹是猜测,Wait() 方法只是等待任务完成。如果任务尚未开始,则在当前线程上执行。但是,如果任务已经开始得更早,它会阻塞当前线程,将当前线程放入等待队列,下次执行调用 Wait 的任务的线程会出现并完成它的工作,它向等待线程发出信号,等待线程继续。因此,在调用 Wait 时会维持任务的线程亲和性。

当然,这一切都只是猜测。我希望有人确认。

最佳答案

It is my understanding that await disassociates any affinity between the thread and the task that was being run on the thread.

不,这根本不是发生的事情。

首先,await 不会导致任何运行,也不会被"dispatch"。在您到达 await 之前,调度(如果有)和运行(如果有)已经在进行中。

await 是一个“异步等待”;也就是说,它异步等待任务完成。 “异步”在这里的意思是“不阻塞当前线程”。

我有更详细的introduction to async and await在我的博客上。

I understand that logically, both would result in the same flow-of-control.

不是真的。 Wait 会阻塞当前线程,而 await 不会。

Under both the cases, the DoIOAsync method would get called only after the CPUBoundWork task has completed execution.

这是正确的。

However, would there be a difference in terms of the scheduling of the CPU task in both the cases?

不,在这两种情况下,调度都是由 Task.Run 完成的,而不是 Waitawait

While this works great for I/O requests, since you now re-use an I/O thread that was blocked on a network driver, you want to maintain thread-affinity for CPU bound work.

如果你想留在同一个线程上,那么你不能使用Task.Run。您必须直接调用 CPUBoundWork

the Wait() method, I am not sure but purely guessing, simply waits for the task to complete. If the task has not yet begun, it executes it on the current thread.

它的意义远不止于此。有时会,有时不会。在您发布的代码中,它通常不会(因为 CPUBoundWork 已经启动)。

Therefore, thread-affinity for the task is maintained when calling Wait.

同样,这是一种简化。如果通过“线程亲和性”你的意思是线程在 Wait 之前和之后是相同的,那么是的,这是正确的。

然而,blocking on tasks within an asynchronous method can be dangerous ;正如我在我的博客中描述的那样,您可能会陷入僵局。如果您正在考虑将 Task.Runasync 结合使用,请查看我的 Task.Run etiquette guide .

关于c# - 在 CPU 绑定(bind)任务上使用 await 关键字与 Task.Wait() 方法有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37603609/

相关文章:

c# - 意外输出打印长数字

c# - 多线程行为时的 CPU 缓存

c# - 如何使用 C# 获取当前事件窗口的标题?

c# - 如何从 CefSharp 3 在 native 浏览器中打开链接

.net - Windows Phone 8 中的 SQLite 错误 - tracker.exe 和 Winmd 文件丢失

c# - 负载测试期间观察到套接字异常

c# - 在编译时捕获对 decimal.ToString 的调用

swift - 应该根据要求执行 segue

ruby - 从流 block 写入文件

c# - 上下文已被处理。执行异步