use*_*000 23 .net c# asynchronous async-await
我想知道是否真的async
- await
不应该用于"高CPU"任务.我在演讲中看到了这一点.
所以我猜这意味着什么
Task<int> calculateMillionthPrimeNumber = CalculateMillionthPrimeNumberAsync();
DoIndependentWork();
int p = await calculateMillionthPrimeNumber;
Run Code Online (Sandbox Code Playgroud)
我的问题是可以在上面是合理的,如果没有,有没有做一个高CPU任务异步的一些其他的例子吗?
事实上,async/await有两个主要用途.一个(我的理解是,这是它被放入框架的主要原因之一)是使调用线程在等待结果时执行其他工作.这主要用于I/O绑定任务(即主要"持有"是某种I/O的任务 - 等待硬盘驱动器,服务器,打印机等响应或完成其任务).
作为旁注,如果你以这种方式使用async/await,重要的是确保你已经实现了它,使得调用线程在等待结果时实际上可以做其他工作; 我见过很多人做"A等待B,等待C"的事情; 这可能最终表现不会比A同时调用B同步而B只是同步调用C(因为调用线程在等待B和C的结果时从不允许做其他工作).
在I/O绑定任务的情况下,创建额外的线程只是为了等待结果是没有意义的.我在这里通常的比喻是考虑在一个有10人的餐馆中订购.如果服务员要求订购的第一个人还没有准备好,那么服务员不会等待他做任何其他人的订单之前做好准备,他也不会带第二个服务员等待第一个人.在这种情况下,最好的办法是询问小组中的其他9人的订单; 希望,到他们订购时,第一个人就会准备好.如果没有,至少服务员仍然节省了一些时间,因为他花了更少的时间闲着.
也可以使用像Task.Run
CPU一样的任务(这是第二次使用).按照我们上面的类比,这是一个案例,通常有更多的服务员是有用的 - 例如,如果一个服务员有太多的桌子供服务.实际上,这实际上是"幕后"的所有内容都是使用线程池; 它是执行CPU绑定工作的几种可能结构之一(例如,只是将它"直接"放在线程池上,显式创建一个新线程,或使用后台工作程序)所以这是一个设计问题,你最终会使用哪种机制.
async/await
这里的一个优点是它可以(在适当的情况下)减少必须手动编写的显式锁定/同步逻辑的数量.这是一个愚蠢的例子:
private static async Task SomeCPUBoundTask()
{
// Insert actual CPU-bound task here using Task.Run
await Task.Delay(100);
}
public static async Task QueueCPUBoundTasks()
{
List<Task> tasks = new List<Task>();
// Queue up however many CPU-bound tasks you want
for (int i = 0; i < 10; i++)
{
// We could just call Task.Run(...) directly here
Task task = SomeCPUBoundTask();
tasks.Add(task);
}
// Wait for all of them to complete
// Note that I don't have to write any explicit locking logic here,
// I just tell the framework to wait for all of them to complete
await Task.WhenAll(tasks);
}
Run Code Online (Sandbox Code Playgroud)
显然,我在这里假设任务是完全可并行化的.另外请注意,您可以在这里自己使用线程池,但这样会有点不太方便,因为您需要某种方法来弄清楚自己是否所有这些都已完成(而不仅仅是让框架弄明白这一点)为了你).您也可以在Parallel.For
这里使用循环.
我想知道async-await是否应该用于"高CPU"任务.
是的,这是真的.
我的问题是上述情况是否合理
我会说这是没有道理的.在一般情况下,您应该避免使用Task.Run
具有异步签名的方法.不要为同步方法公开异步包装器.这是为了防止消费者混淆,特别是在ASP.NET上.
然而,没有什么错误使用Task.Run
来调用一个同步的方法,例如,在UI应用程序.通过这种方式,您可以使用多线程(Task.Run
)来保持UI线程的自由,并使用以下方式优雅地使用它await
:
var task = Task.Run(() => CalculateMillionthPrimeNumber());
DoIndependentWork();
var prime = await task;
Run Code Online (Sandbox Code Playgroud)