异步等待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*/ }
如果异步
方法( 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操作),我有一个 Task 为 CalcFirstMillionsDigitsOf_PI_Async $怎么办? c $ c>(在一个单线程上进行大量的计算绑定操作)
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 :
- 保留的线程上下文
- 抛出异常
-
Caller 线程未被阻止
- 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 .
我的诊断是否正确?
推荐答案
实际上,在两种情况下,您只能获得 second 的优点。 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调用方法 ... ugh!',作者是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完成机制。甚至还有一个特殊的ThreadPool,您可以将其与Tasks 使用自定义TaskScheduler
- 有些人会将TaskCompletionSource包装在事件或回调之类的另一种机制上。
在每种情况下,都是释放线程(如果使用了线程)的特定实现。 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.
EDIT
使用反编译器,可能会看到 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屋!