C# 对使用task.Run()创建的任务调用wait

C# 对使用task.Run()创建的任务调用wait,c#,.net,task-parallel-library,async-await,C#,.net,Task Parallel Library,Async Await,为什么在C#中可以这样做 Task.Run()不应该用于CPU绑定的代码吗?为此调用wait有意义吗 例如,调用Task.Run后,我知道任务正在线程池的另一个线程中运行。打电话给Wait的目的是什么?仅仅调用task.Wait(),没有什么意义吗 最后一个问题,我的第一印象是await专门用于async方法。将其用于task.Run()返回的任务是否常见 编辑。这也让我想知道,为什么我们有Task.Wait()而没有Task.Wait()。我的意思是,为什么一个方法用于Wait()而一个key

为什么在C#中可以这样做

Task.Run()
不应该用于CPU绑定的代码吗?为此调用
wait
有意义吗

例如,调用
Task.Run
后,我知道任务正在线程池的另一个线程中运行。打电话给Wait的目的是什么?仅仅调用
task.Wait()
,没有什么意义吗

最后一个问题,我的第一印象是
await
专门用于
async
方法。将其用于
task.Run()返回的任务是否常见


编辑。这也让我想知道,为什么我们有
Task.Wait()
而没有
Task.Wait()
。我的意思是,为什么一个方法用于
Wait()
而一个keyworkd用于
Wait
。在这两种情况下使用一种方法不是更为一致吗?

使用
Wait
毫无意义。如果你只是想让另一个线程坐在那里无所事事地等待,那么启动一个新线程来完成工作是没有意义的。这两种方法中唯一明智的选择是等待它。等待任务是完全合理的,因为它允许原始线程继续执行


等待
任何类型的
任务
(在正确的上下文中)都是明智的,不管它来自哪里。等待的
async
方法没有什么特别之处。事实上,在每一个异步程序中,都需要有不使用
async
关键字的异步方法;如果每个
wait
都在等待一个
async
方法,那么您将永远没有任何地方可以开始。

是的,这是常见的,也是推荐的<代码>等待
允许异步等待任务(或任何可等待的任务)。诚然,它主要用于自然异步操作(如I/O),但也用于使用
任务卸载要在不同线程上完成的工作。运行
并异步等待它完成

使用
Wait
不仅会阻塞调用线程,因此无法达到使用
Task.Run的目的。首先,它还可能在具有单线程同步上下文的GUI环境中导致死锁

最后一个问题,我的第一印象是wait专门用于异步方法


方法是否实际标记了
async
修饰符是一个实现细节,而.Net中的大多数“根”任务返回方法实际上并不是
async
方法(
task.Delay
就是一个很好的例子)。

这对于类似这样的情况非常常见且有用(大大简化;例如,生产代码需要异常处理):

关于您稍后编辑的注释,“wait”不是方法调用。它是一个关键字(为了清楚起见,仅允许在标记为“async”的方法中使用)编译器用来决定如何实现该方法的。在后台,这涉及将方法过程重写为一个状态机,每次使用“wait”关键字时可以暂停该状态机,然后在等待调用时恢复,以指示已完成。这是一个简化的描述(异常传播和其他细节使事情变得复杂),但关键的一点是“wait”不仅仅是在任务上调用一个方法

在以前的C#版本中,最接近这种“async/await”魔术的构造是使用“yield return”来实现
IEnumerable
。对于枚举和异步方法,都需要一种暂停和恢复方法的方法。async/await关键字(以及相关的编译器支持)从可恢复方法的基本思想开始,然后添加一些强大的功能,如异常的自动传播、通过同步上下文调度回调(主要用于将代码保留在UI线程上)和自动实现所有粘合代码以设置连续回调逻辑

仅仅调用task.Wait()是没有意义的

否,如果调用
Wait
您在那里涉及两个线程,则线程池中的一个工作线程正在为您工作(假定任务受CPU限制),并且您的调用线程也将被阻止

为什么要阻止调用线程?如果调用线程是UI线程,那么结果将非常糟糕!如果调用
任务,也会如此。立即运行
然后执行
任务。等待
也会使情况变得更糟。这并不比同步调用委托好。立即调用
等待
没有任何意义在开始一项任务之后


您几乎不应该使用
Wait
,始终更喜欢
Wait
并释放调用线程。

这里有几个很好的答案,但从更哲学的角度来看

如果您有大量CPU受限的工作要做,最好的解决方案通常是任务并行库,即,
Parallel
或Parallel LINQ

如果您有I/O绑定的工作要做,最好的解决方案通常是
async
await
围绕自然异步实现构建的代码(例如
Task.Factory.fromsync

Task.Run
是一种执行单个CPU绑定代码并从调用线程的角度将其视为异步的方法。也就是说,如果您希望执行CPU绑定的工作,但不让它干扰UI

构造
await Task.Run
是一种连接两个世界的方法:让UI线程排队处理CPU绑定的工作并异步处理。这也是连接异步和并行代码的最佳方法,例如
await Task.Run(()=>parallel.ForEach(…)

为什么Wait()使用方法,Wait()使用关键字

awai的一个原因
var task = Task.Run (...);
await task;
async void OnButtonClicked()
{
   //... Get information from UI controls ...
   var results = await Task.Run(CpuBoundWorkThatShouldntBlockUI);
   //... Update UI based on results from work run in the background ...
}