【问题标题】:call method async inside Task.Run在 Task.Run 中调用异步方法
【发布时间】:2020-03-13 20:09:40
【问题描述】:

下面显示的代码在 asp.net mvc 应用程序中执行

public async Task<string> GetCustomers1(){
    return await getcustomer1Async();
}
public async Task<string> GetCustomers2(){
    return await getcustomer2Async();
}
public async Task<JsonResult> Index(){
   var result1 =Task.Run(()=>GetCustomers1());
   var result2 =Task.Run(()=>GetCustomers2());
   Task.WaitAll(result1,result2);

}

我很清楚任务运行会创建两个线程来执行GetCustomers1、GetCustomers2方法。 - 我的问题是当GetCustomers1和GetCustomers2方法到达有await这个词的行时,不完整的任务应该返回,不完整的任务应该返回到哪里?线程是否返回线程池? -Task.WaitAll 在其他任务完成运行之前,你会让主线程忙吗?

我知道如果方法是异步的,你不应该使用 tak.run。但我想知道在这种情况下代码在内部是如何工作的。

【问题讨论】:

    标签: asp.net-mvc performance async-await task-parallel-library


    【解决方案1】:

    我很清楚任务运行会创建两个线程来执行GetCustomers1、GetCustomers2方法。

    Task.Run 不创建线程。它将工作排队到线程池。

    我的问题是当GetCustomers1和GetCustomers2方法到达有await这个词的行时,不完整的任务应该返回,不完整的任务应该返回到哪里?线程是否返回线程池?

    是的,线程返回到线程池。当await 准备好恢复执行时,该方法的“继续”将排队到线程池中。请注意,延续可能会或可能不会在同一线程上运行;它们可以在任何线程池线程上运行。

    Task.WaitAll 在其他任务完成运行之前,您会让主线程忙吗?

    是的,Task.WaitAll 会这样做。它还会阻塞异步代码,这不是一个好主意。最好去async all the way

    我知道如果方法是异步的,你不应该使用 tak.run。

    Task.Run 用于异步代码很好。但在一般情况下,您不应该在 ASP.NET 上使用Task.Run,因为它将工作排入线程池,而不是让 ASP.NET 完全控制线程池。相反,直接调用异步代码并使用异步代码(Task.WhenAll)而不是阻塞代码(Task.WaitAll):

    public async Task<string> GetCustomers1() {
      return await getcustomer1Async();
    }
    public async Task<string> GetCustomers2(){
      return await getcustomer2Async();
    }
    public async Task<JsonResult> Index(){
      var result1 = GetCustomers1();
      var result2 = GetCustomers2();
      await Task.WhenAll(result1, result2);
    }
    

    【讨论】:

    • (1/2) 嗨 stephen Task.Run 不创建线程。它将工作排队到线程池你是什么意思? Run 方法是否将代码排队以在不同的线程上运行?
    • (2/2) 代码 (Task.WhenAll) 而不是阻塞代码 (Task.WaitAll):示例 var a = await ascyn1(); var b =等待 asynci2();任务.whenall(a,b); a 和 b 并行运行?如果是,是否创建了新线程?如果没有,内部会发生什么?
    • 线程池是线程池。 Task.Run 将代码排入队列以在其中一个线程上运行。 ab 同时运行;异步代码doesn't block a threadWaitAll 可以单独使用 cause a deadlock,但在这种情况下 Task.Run 可以避免死锁。
    • Task.Run 不创建线程。将线程池排队以在其中一个线程上运行。总之,该任务不会创建线程。但是如果它在其中一个线程中执行这些任务的代码呢?如果是这样,那么您对资源的使用不当。
    • @developer 我不确定你在说什么。
    【解决方案2】:

    是的,在await 行,方法GetCustomers1GetCustomers2 将立即返回一个不完整的任务,假设从getcustomer1Async()getcustomers2Async() 返回的任务是不完整的。 await 关键字允许您在 await 行下方编写代码,该代码将在等待的任务完成后运行。在您的情况下,等待行下方没有代码,因此您也可以直接返回任务而不等待它们:

    public Task<string> GetCustomers1()
    {
        return getcustomer1Async();
    }
    

    请注意,不仅await 关键字消失了,async 也消失了。

    至于Index 方法,它应该给你一个编译时警告,因为在用async 关键字标记的方法中没有await。您可能应该将其修改为以下内容:

    public async Task<JsonResult> Index()
    {
       var task1 = Task.Run(() => GetCustomers1());
       var task2 = Task.Run(() => GetCustomers2());
       string[] results = await Task.WhenAll(task1, task2);
       //...use the results to create a JsonResult and return it
    }
    

    最后请记住,在返回Task 的方法中添加后缀Async 是一种常见的做法。所以方法GetCustomers1应该重命名GetCustomers1AsyncIndex应该重命名IndexAsync等等。你可以阅读相关指南here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-12-28
      • 2023-04-06
      • 2017-03-12
      • 1970-01-01
      • 2019-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多