【问题标题】:await async code seems to still be running sync等待异步代码似乎仍在运行同步
【发布时间】:2017-07-07 15:25:58
【问题描述】:

我是 async / await 的新手,一直在尝试在我的 4.6 web api 2 项目中实现它。

public class MyController : ApiController
{
     public async Task<Thing> Search(String searchTerms)
{
    myThing = new Thing();
    myThing.FirstProperty = await doFirstPropertyAsync(searchTerms);
    myThing.SecondProperty = await doSecondPropertyAsync(searchTerms);

 return myThing;

}
}

基本上,我返回一个类 (Thing),它有两个属性,每个属性都需要几秒钟来填充。我实际上加载了大约 10 个属性,但它们的逻辑相同。

    public async Task<MyCoolSubObject> doFirstPropertyAsync(string searchTerms)
    {
        SomeController sController = new SomeController();
        Debug.WriteLine("first - starting.");

        var x = await Task.Run(()=>sController.Lookup(searchTerms));

        Debug.WriteLine("first - finishing.");
        return x;
    }

    public async Task<MyCoolSubObject> doSecondPropertyAsync(string searchTerms)
    {
        SomeOtherController sController = new SomeOtherController();
        Debug.WriteLine("second - starting.");

        var x = await Task.Run(()=>sController.Lookup(searchTerms));

        Debug.WriteLine("second - finishing.");
        return x;
    }

是什么让我摸不着头脑:

当我查看调试输出时,第一个属性分配方法调用开始并在第二个完成之前完成。同样,我实际上有其中的十个,无论我将属性分配按什么顺序排列,它们都以串行方式完成(即:在另一个完成之前什么都没有开始)。

这些属性分配基本上是在执行需要一段时间的数据库调用,因此我希望它们尽可能并行运行。方法本身( SomeController.Lookup(string) )不包含等待/异步/任务的东西。

【问题讨论】:

  • “当我查看调试输出时,第一个属性分配方法调用开始并在第二个完成之前完成”,这听起来很准确。如果您希望这些并行运行,async/await 可能不是正确的工具。 Promise.all() 会更有用。
  • 串行运行(一个语句接着另一个语句),而不是“同步”(阻塞一个线程)。这就是await 所做的;要同时执行多个异步操作,请使用Task.WhenAll。此外,您不应该在 ASP.NET 上使用 Task.Run - 这种异步过同步首先破坏了异步代码的目的。

标签: async-await asp.net-web-api2 task-parallel-library .net-4.6


【解决方案1】:

再一次,我实际上有十个这样的,不管我是什么顺序 将属性分配放入它们以串行方式完成(即: 在另一个完成之前,什么都没有开始)。

发生这种情况是因为在您的代码中,您在启动任务后立即使用 await 关键字,这样做会阻止方法在任务完成之前继续执行下一条语句。

如果您想并行运行任务,您应该启动所有任务,然后使用 Task.WhenAll 等待所有任务:

public async Task<Thing> Search(String searchTerms)
{
    myThing = new Thing();
    var firstTask = doFirstPropertyAsync(searchTerms);
    var secondTask = doSecondPropertyAsync(searchTerms);
    await Task.WhenAll(firstTask, secondTask);
    myThing.FirstProperty = await firstTask;
    myThing.SecondProperty = await secondTask;
    return myThing;
}

请注意,当我们在 await Task.WhenAll 任务已经完成之后分别等待每个任务时,我们这样做是为了从任务中获取结果,尽管我们可以使用 Result 属性(它不会阻塞,因为我们知道任务已经完成)出于一致性原因,我更喜欢使用 await。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-27
    • 2020-12-02
    相关资源
    最近更新 更多