我应该什么时候等待我的asyncs?

Jac*_*ger 48 .net c# async-await

我们目前正在重构我们项目的各个部分上下异步,是的!

由于我们的理解不同,我和同事(让我们称他为吉姆)对于我们的异步/等待代码将如何执行以及编写它的方式有不同的看法.

以下是Jim写的示例方法:

public async Task<HouseModel> GetHouseModel(Guid houseId)
{
    House house = await _houseService.GetHouse(houseId);

    Task<IEnumerable<Furniture>> furniture = _furnitureService.GetFurnitureForHouse(house);

    Task<IEnumerable<Appliances>> appliances = _applianceService.GetAppliancesForHouse(house);

    return _houseModelFactory.MakeHouseModel(await furniture, await appliances);
}
Run Code Online (Sandbox Code Playgroud)

以及如何编写它的示例:

public async Task<HouseModel> GetHouseModel(Guid houseId)
{
    House house = await _houseService.GetHouse(houseId);

    IEnumerable<Furniture> furniture = await _furnitureService.GetFurnitureForHouse(house);

    IEnumerable<Appliances> appliances = await _applianceService.GetAppliancesForHouse(house);

    return _houseModelFactory.MakeHouseModel(furniture, appliances);
}
Run Code Online (Sandbox Code Playgroud)

我的理解是:因为上面的服务furnitureappliance服务中的方法都需要House,所以House在继续之前它们会等待可用.然后,两个需要的方法House都会运行,但第二个方法(GetAppliancesForHouse)不会等到第一个方法在开始之前完成.

吉姆的理解是:我们应该只在需要时才等待这两种方法.这样他们就会彼此平行.他认为按照我的方式做,将导致第二种方法等待第一种方法,即:GetAppliancesForHouse等待GetFurnitureForHouse.

这些理解中的任何一个是否正确?或者我们一直在进行弥补?我们何时应该等待?

Ern*_*dob 49

我的理解是:因为上述家具和家电服务的方法都要求House,他们会等待House继续使用.

你的理解是错误的.需要House的方法,他们不等你拿到House因为你需要它.他们不解决他们的依赖关系以及何时等待代码或不自己.代码等待获得Houses,因为你有await.它不知道接下来会发生什么.

然后,两个需要House的方法都会运行,但第二个方法(GetAppliancesForHouse)不会在开始之前等待第一个方法完成.

类似地,GetAppliancesForHouse如果它应该等待或不基于依赖性,它将不会有自己的理解.GetAppliancesForHouse将无法运行,因为您的代码GetFurnitureForHouse首先要等待它.您的代码将始终按顺序运行.

吉姆的理解是:我们应该只在需要时才等待这两种方法.这样他们就会彼此平行.

这通常是正确的.正如其他人所指出的那样,代码仍然可能并不依赖于其他因素.此外,可能有合理的理由不希望并行运行代码.

他认为按照我的方式进行操作将导致第二种方法等待第一种方法,即:GetAppliancesForHouse等待GetFurnitureForHouse.

他是对的.

要查看确切的结果,您可以放置​​断点并查看每行后发生的情况.在Jims案例中,从家具到家用电器之后,家具变量还没有价值,它仍然是一项任务,但你已经在下一行了.

根据你的情况,去家电系列,你会看到家具已经有了价值,因为它等待它.

  • @AdamSimon总是要考虑潜在的线程问题,这就是理解async/await如何工作的重要原因. (5认同)
  • @CamiloTerevinto是对的.另外,我要指出**Jim的方式可能会引入线程问题**.例如,如果EF用于数据访问并且*_applianceService*和*_furnitureService*共享相同的DbContext实例,则会出现问题,因为[DbContext不是线程安全的](/sf/ask/428863151/ -dbcontext线程安全的). (4认同)

SO *_*ood 8

无论你是正确的,看到答案@erndob的原因.但是,其中一个问题没有得到解答:

我们何时应该等待?

  • 你想要按顺序完成工作吗?用你的方式.
  • 你想要并行完成工作吗?用吉姆的方式.

:吉姆的方式实际上并不会以并行方式运行,如果任务计划程序使用的是不能在同一时间运行两个任务,例如,由于缺乏系统资源(感谢@AdamSimon).