【问题标题】:Multiple Task in one controller一个控制器中的多个任务
【发布时间】:2016-09-02 18:03:37
【问题描述】:

我有一个执行 n 步的 MVC 控制器动作 喜欢

Public ActionResult Index()
{
    GetDatFromTabelCustomer()
    GetDataFromWebApi()
    GetDataFromSession()
    GetyetAnotherData()
    SendItToView()
}

我打算用Task.Run 包装每个方法 然后在 i Process 和 SendItToView() 之前执行 Task.WhenAll() 但是有很多博客介绍了为什么不应该使用 Task.Run 而是做异步等待,在这种情况下,我真的想运行并行任务而不是以串行方式等待每个任务, 这样做需要从线程池中缝合和拆除线程,但除了 Task.Run 之外,我还有什么其他选择?

示例

Public ActionResult Index()
{
    Task taska = Task.Run(() => GetDatFromTabelCustomer())
    Task taskb = Task.Run(() => GetDataFromWebApi())
    Task taskc = Task.Run(() => GetDataFromSession())
    Task taskd = Task.Run(() => GetyetAnotherData())
    await taska;
    await taskb;
    await taskc;
    await taskd;

    string get resultA = taska.Result
    .
    .
    .
    SendItToView()
}

【问题讨论】:

  • 您的示例没有意义,在代码的第一位GetDatFromTabelCustomer() 没有返回任何内容,但在第二个示例中它看起来返回了string

标签: vb.net multithreading async-await task


【解决方案1】:

“正确”的做法是将你的函数重写为异步而不是重写为异步,你可以将 Task.Run() 用于不公开异步 API 的函数。您还可以使用Task.WhenAll( 将所有任务合并到一个可等待的事物中。

public async Task<ActionResult> IndexAsync()
{
    Task<string> taska = GetDatFromTabelCustomerAsync());
    Task taskb = GetDataFromWebApiAsync());
    Task taskc = Task.Run( () =>     GetDataFromSession());
    Task taskd = Task.Run( () =>      GetyetAnotherData());

    await Task.WhenAll(taska, taskb, taskc, taskd);

    string resultA = await taska;

    SendItToView()
}

在您的示例中,您展示了 taska 返回一个字符串,我修复了代码来执行此操作。在任务上第二次调用await 是免费的,养成一个比调用taska.Result 更好的习惯,你永远不应该在异步方法中调用.Result

Here is a good article 解释如何从同步 MVC 代码转换为异步 MVC 代码

【讨论】:

    【解决方案2】:

    这些似乎都是 IO 密集型操作,所以我怀疑使用 Task.Run() 真的不是这里的方法。但是,您仍然可以使用 Task.WhenAll()。您的每个方法都必须返回一个任务,并且可能会使用异步模式来完成它们的工作。然后,执行以下操作:

    var tasks = new List<Task>()
    tasks.Add(GetDataFromTableCustomer());
    tasks.Add(GetDataFromWebApi());
    ...
    await Task.WhenAll(tasks);
    

    此外,由于这些方法返回 Task,因此最好在它们的名称后面加上 Async。

    【讨论】:

      【解决方案3】:

      您不应该使用Task.Run。你想要的是 concurrency(一次做多个事情),而不是 parallelism(一次在不同线程上做多个事情)。并行是并发的一种形式,但您也可以使用Task.WhenAll 进行异步并发

      要正确解决这个问题,首先从您的“叶子”开始,即实际的数据库调用、WebAPI 调用等。使这些端点异步(例如,使用 EF 的异步查询或HttpClient),然后让async 从那里成长。最终,您将得到 GetDataFromTableCustomerAsyncGetDataFromWebApiAsync 方法,然后您可以在控制器方法中使用它们:

      public async Task<ActionResult> Index()
      {
        var taska = GetDataFromTableCustomerAsync();
        var taskb = GetDataFromWebApiAsync();
      
        // Both the db query and WebAPI calls are in progress at this point.
        // So do anything *synchronous* that you want to do.
        // For example, reading session data is not I/O-bound; it should just be done synchronously.
        var sessionData = GetDataFromSession();
      
        // Now, (asynchronously) wait for all the asynchronous work to complete.
        await Task.WhenAll(taska, taskb);
      
        // And get the results.
        var resultA = await taska;
        var resultB = await taskb;
      
        SendItToView();
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-03
        • 2011-09-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多