等待异步代码似乎仍然是 运行 同步

await async code seems to still be running sync

我是 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;

}
}

基本上我要返回一个 class (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) ) 不包含 await/async/task 内容。

Again, I actually have like ten of these and no matter what order I put the property assignments in they complete in a serial fashion (ie: nothing starts until another one finishes).

发生这种情况是因为在您的代码中,您在启动任务后立即使用 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;
}

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