我仍然无法理解 async/await。我想弄清楚是否需要将我的 CPU 密集型工作负载包装在下面的 Task.Run 中。有人能告诉我哪种方法更好吗?
没有 Task.Run:
public async Task ProcessData()
{
//Get some data
var httpClient = new HttpClient();
var response = await httpClient.GetAsync("myUrl");
string data = await response.Content.ReadAsStringAsync();
//Calculate result
string result = null;
for (int i = 0; i < 10000000; i++)
{
//Do some CPU intensive work
}
//Save results
using (var fs = new FileStream("myFile.txt", FileMode.Create))
using (var writer = new StreamWriter(fs))
{
await writer.WriteLineAsync(result);
}
}
Run Code Online (Sandbox Code Playgroud)
使用 Task.Run:
public async Task ProcessData()
{
//Get some data
var httpClient = new HttpClient();
var response = await httpClient.GetAsync("myUrl");
string data = await response.Content.ReadAsStringAsync();
//Calculate result
string result = null;
await Task.Run(() =>
{
for (int i = 0; i < 10000000; i++)
{
//Do some CPU intensive work
}
});
//Save results
using (var fs = new FileStream("myFile.txt", FileMode.Create))
using (var writer = new StreamWriter(fs))
{
await writer.WriteLineAsync(result);
}
}
Run Code Online (Sandbox Code Playgroud)
我的直觉是不使用 Task.Run 但在这种情况下,这是否意味着异步方法中的所有代码都将在单独的线程上执行?这意味着调用线程直到最后才会被中断(文件流关闭并且方法结束)?
或者调用者线程是否会被中断并返回到此方法先执行 CPU 密集型部分,然后再返回到它正在执行的任何操作,而 ProcessData() 在后台运行 FileStream 部分?
我希望这很清楚。
提前致谢
正如我在async intro 中所描述的,一个async方法开始执行,就像任何其他方法一样,直接在调用线程的堆栈上执行。当一个await异步操作时,它将捕获一个“上下文”,“暂停”该方法,并返回给它的调用者。稍后,当“异步等待” ( await) 完成时,该方法将在该捕获的上下文上恢复。
所以,这意味着:
这是否意味着异步方法中的所有代码都将在单独的线程上执行?
没有单独的线程。根本没有线程“执行”,await因为无事可做。当await完成时,该方法继续在所捕获上下文中执行。有时这意味着该方法排队到一个消息队列,它最终将由原始调用线程运行(例如,UI 应用程序以这种方式工作)。其他时候这意味着该方法由任何可用的线程池线程运行(大多数其他应用程序以这种方式工作)。
这意味着调用线程直到最后才会被中断(文件流关闭并且方法结束)?或者调用者线程是否会被中断并返回到此方法先执行 CPU 密集型部分,然后再返回到它正在执行的任何操作,而 ProcessData() 在后台运行 FileStream 部分?
调用线程永远不会被中断。
工作的 CPU 绑定部分将在await. 这可以是原始线程,也可以是线程池线程,具体取决于上下文。
那么,回到最初的问题:
有人能告诉我哪种方法更好吗?
如果这是可以从不同上下文调用的代码,那么我建议不要使用Task.Run,但我建议记录该方法确实执行 CPU 密集型工作。这样,如果调用者从 UI 线程调用此方法,则它知道Task.Run在调用它时使用该方法,以确保 UI 线程不被阻塞。
| 归档时间: |
|
| 查看次数: |
119 次 |
| 最近记录: |