在CPU绑定任务上使用await关键字与Task.Wait()方法之间的区别是什么?

Wat*_* v2 3 .net c# asynchronous task-parallel-library async-await

两者之间的机械差异是什么?

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();
}
Run Code Online (Sandbox Code Playgroud)

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

但是,在两种情况下,CPU任务的调度方面是否存在差异?

更新

请确认我对上述代码的未经教育的反思是否正确.

根据我的理解,await解除了线程与线程上运行的任务之间的任何关联.虽然这对I/O请求非常有用,但由于您现在重新使用在网络驱动程序上阻止的I/O线程,因此您希望保持与CPU绑定工作的线程关联.

虽然等待破坏这种亲和力,Wait()但我不确定但纯粹猜测的方法只是等待任务完成.如果任务尚未开始,则在当前线程上执行该任务.但是,如果任务早先已经开始,它会阻塞当前线程,将当前线程放在等待队列上,下一次执行Wait被调用任务的线程到来并完成其工作时,它会发出信号等待线程和等待线程继续.因此,在调用时会保持任务的线程关联性Wait.

当然,所有这些仅仅是猜测.我希望有人确认一下.

Ste*_*ary 7

我的理解是等待解除线程与线程上运行的任务之间的任何关联.

不,这根本不会发生什么.

首先,await没有任何东西可以运行,没有任何"预定".在你到达之前,调度(如果有的话)和正在运行(如果有的话)已经在进行中await.

await是一个"异步等待"; 也就是说,它异步等待任务完成."异步"在这里表示"不阻塞当前线程".

我有一个更详细的介绍async,并await在我的博客.

我从逻辑上理解,两者都会产生相同的控制流.

并不是的.在Wait将阻止当前线程,而await不会.

在这两种情况下,只有在CPUBoundWork任务完成执行后才会调用DoIOAsync方法.

这是对的.

但是,在两种情况下,CPU任务的调度方面是否存在差异?

不,在这两种情况下,调度都是通过Task.Run,而不是Wait或完成的await.

虽然这对I/O请求非常有用,但由于您现在重新使用在网络驱动程序上阻止的I/O线程,因此您希望保持与CPU绑定工作的线程关联.

如果你想留在同一个线程,那么你就无法使用Task.Run.你必须CPUBoundWork直接打电话.

Wait()方法,我不确定,但纯粹猜测,只是等待任务完成.如果任务尚未开始,则在当前线程上执行该任务.

还有更多的东西.有时它会,有时它不会.在您发布的代码中,通常不会(因为CPUBoundWork已经开始).

因此,在调用Wait时会保持对任务的线程关联.

同样,这是一种简化.如果通过"线程亲和力"表示线程在之前和之后是相同的Wait,那么是的,这是正确的.

但是,在异步方法中阻塞任务可能很危险 ; 正如我在博客中描述的那样,你可以陷入僵局.如果你正在考虑使用Task.Run与配合async,请查看我的Task.Run礼仪指导.