c# - 如何处理具有一些等待和一些 cpu 绑定(bind)操作的异步方法

标签 c# 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);
    }
}

使用 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);
    }
}

我的直觉是不使用 Task.Run,​​但在这种情况下,这是否意味着异步方法中的所有代码都将在单独的线程上执行?意味着调用线程直到最后才会被中断(文件流关闭并且方法结束)?

或者调用者线程是否会被中断并返回此方法首先执行 CPU 密集型部分,然后在 ProcessData() 为 FileStream 部分在后台运行时返回到它正在执行的任何操作?

我希望这很清楚。

提前致谢

最佳答案

如我的 async intro 中所述,async 方法开始执行,就像任何其他方法一样,直接在调用线程的堆栈上。当 await 异步执行时,它将捕获“上下文”,“暂停”该方法,然后返回给它的调用者。稍后,当“异步等待”(await)完成时,该方法会在捕获的上下文中恢复。

所以,这意味着:

would that mean that all code in an async method is going to be executed on a separate thread?

There is no separate thread .根本没有线程“执行” await 因为没有什么可做的。当 await 完成时,该方法继续在捕获的上下文中执行。有时这意味着该方法排队到消息队列中,最终将由原始调用线程运行(例如,UI 应用程序以这种方式工作)。其他时候,这意味着该方法由任何可用的线程池线程运行(大多数其他应用程序都以这种方式工作)。

Meaning the calling thread will not be interrupted until the very end (File stream is closed and method ends)? Or will the caller thread be interrupted and go back to this method to do the CPU intensive part first and then go back to whatever it was doing while ProcessData() runs in the background for the FileStream part?

调用线程永远不会中断。

工作的 CPU 绑定(bind)部分将在 await 点捕获的任何“上下文”上运行。这可以是原始线程,也可以是线程池线程,具体取决于上下文。

那么,回到原来的问题:

Can someone tell me which is the better way to do this?

如果这是可以从不同上下文调用的代码,那么我建议不要使用 Task.Run,但我建议记录该方法确实执行 CPU 密集型工作。这样,如果调用者从 UI 线程调用此方法,则它知道在调用它时使用 Task.Run,以确保 UI 线程不会被阻塞。

关于c# - 如何处理具有一些等待和一些 cpu 绑定(bind)操作的异步方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60876295/

相关文章:

vue.js - 从异步 Vuex 操作中捕获组件中的错误

c# - .ContinueWith() 的竞争条件

c# - Tridion 2009 待定 : How do I determine if a Page is published to particular publication target?

javascript - 从 Javascript 调用 PUT 方法

c# - MSBuild 从输出中排除附属程序集

c# - 对锯齿状字符串数组使用 foreach 循环来显示其中的元素?

C# EPPlus 数据栏条件格式与纯色填充

javascript - Async/Await 导致循环

javascript - Asyncawait.js 回调中的多个参数

c# - 为什么我的异步程序抛出 NullReferenceException