异步等待 CPU 计算与 IO 操作的用法? [英] async await usages for CPU computing vs IO operation?
问题描述
我已经知道 async-await
保持线程上下文,还处理异常转发等(这有很大帮助).
I already know that async-await
keeps the thread context , also handle exception forwarding etc.(which helps a lot).
但请考虑以下示例:
/*1*/ public async Task<int> ExampleMethodAsync()
/*2*/ {
/*3*/ var httpClient = new HttpClient();
/*4*/
/*5*/ //start async task...
/*6*/ Task<string> contentsTask = httpClient.GetStringAsync("http://msdn.microsoft.com");
/*7*/
/*8*/ //wait and return...
/*9*/ string contents = await contentsTask;
/*10*/
/*11*/ //get the length...
/*12*/ int exampleInt = contents.Length;
/*13*/
/*14*/ //return the length...
/*15*/ return exampleInt;
/*16*/ }
如果 async
方法 (httpClient.GetStringAsync
) 是一个 IO 操作(就像我上面的示例一样)那么 - 我获得了这些东西:
If the async
method (httpClient.GetStringAsync
) is an IO operation ( like in my sample above) So - I gain these things :
- 调用者线程未被阻塞
Worker 线程被释放,因为有一个 IO 操作(IO 完成端口...)(GetStringAsync 使用TaskCompletionSource
而不是打开一个新线程)- 保留的线程上下文
- 抛出异常
- Caller Thread is not blocked
Worker thread is released because there is an IO operation ( IO completion ports...)(GetStringAsync usesTaskCompletionSource
and not open a new thread)- Preserved thread context
- Exception is thrown back
但是如果不是 httpClient.GetStringAsync
(IO 操作),我有一个 CalcFirstMillionsDigitsOf_PI_Async
的 Task(在单独的线程)
But What if instead of httpClient.GetStringAsync
(IO operation) , I have a Task of CalcFirstMillionsDigitsOf_PI_Async
(heavy compute bound operation on a sperate thread)
似乎我在这里得到的唯一东西是:
It seems that the only things I gain here is :
- 保留的线程上下文
- 抛出异常
- 调用者线程未被阻塞
- Preserved thread context
- Exception is thrown back
- Caller Thread is not blocked
但我还有另一个线程(并行线程)来执行操作.并且cpu在主线程和操作之间切换.
But I still have another thread ( parallel thread) which executes the operation. and the cpu is switching between the main thread and the operation .
我的诊断是否正确?
推荐答案
实际上,在这两种情况下,您只会获得第二组优势.await
不会启动任何异步执行,它只是编译器生成处理完成、上下文等代码的关键字.
Actually, you only get the second set of advantages in both cases. await
doesn't start asynchronous execution of anything, it's simply a keyword to the compiler to generate code for handling completion, context etc.
您可以在"使用 await 调用方法"...呃!' by Stephen Toub.
You can find a better explanation of this in '"Invoke the method with await"... ugh!' by Stephen Toub.
由异步方法本身决定如何实现异步执行:
It's up to the asynchronous method itself to decide how it achieves the asynchronous execution:
- 有些方法会使用 Task 在 ThreadPool 线程上运行它们的代码,
- 有些人会使用一些 IO 完成机制.甚至还有一个特殊的线程池,您可以将其与任务一起使用 使用自定义 TaskScheduler
- 有些人会将 TaskCompletionSource 包装在另一种机制上,例如事件或回调.
在每种情况下,释放线程的都是特定的实现(如果使用了的话).当 Task 完成执行时,TaskScheduler 会自动释放线程,因此无论如何您都可以在案例 #1 和 #2 中获得此功能.
In every case, it is the specific implementation that releases the thread (if one is used). The TaskScheduler releases the thread automatically when a Task finishes execution, so you get this functionality for cases #1 and #2 anyway.
如果回调 #3 会发生什么,取决于回调是如何进行的.大多数情况下,回调是在某个外部库管理的线程上进行的.在这种情况下,您必须快速处理回调并返回以允许库重用该方法.
What happens in case #3 for callbacks, depends on how the callback is made. Most of the time the callback is made on a thread managed by some external library. In this case you have to quickly process the callback and return to allow the library to reuse the method.
编辑
使用反编译器,可以看到 GetStringAsync
使用第三个选项:它创建一个 TaskCompletionSource,在操作完成时收到信号.执行操作委托给 HttpMessageHandler.
Using a decompiler, it's possible to see that GetStringAsync
uses the third option: It creates a TaskCompletionSource that gets signalled when the operation finishes. Executing the operation is delegated to an HttpMessageHandler.
这篇关于异步等待 CPU 计算与 IO 操作的用法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!