web-dev-qa-db-fra.com

Quand dois-je attendre mes asyncs?

Nous refactorisons actuellement des sections de notre projet pour qu'elles soient asynchronisées de haut en bas, yay!

En raison de notre compréhension différente, moi et un collègue (appelons-le Jim), avons des opinions différentes sur la façon dont notre code asynchrone/attente s'exécutera et sur la façon de l'écrire.

Voici l'exemple de méthode que Jim a écrit:

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);
}

Et l'exemple de la façon dont je l'écrirais:

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);
}

Ma compréhension est la suivante: étant donné que les méthodes des services furniture et appliance ci-dessus nécessitent House, elles attendront que House soit disponible avant de continuer . Ensuite, les deux méthodes qui nécessitent House s'exécuteront, mais la deuxième méthode (GetAppliancesForHouse) n'attendra pas la fin de la première avant de démarrer.

La compréhension de Jim est la suivante: nous ne devons attendre les deux méthodes que lorsqu'elles sont nécessaires. Pour qu'ils fonctionnent tous les deux parallèlement. Il pense que si je le fais à ma façon, la deuxième méthode attendra la première, c'est-à-dire: GetAppliancesForHouse attendant GetFurnitureForHouse.

Certaines de ces interprétations sont-elles correctes? Ou avons-nous simplement inventé au fur et à mesure? Quand faut-il attendre?

48
Jack Pettinger

Ma compréhension est la suivante: parce que les méthodes des services d'ameublement et d'appareils électroménagers décrites ci-dessus nécessitent House, ils attendront que House soit disponible avant de continuer.

Votre compréhension est fausse. Les méthodes qui nécessitent House, ils n'attendent pas que vous obteniez House parce que vous en avez besoin. Ils ne résolvent pas leurs dépendances et quand attendre le code ou non par eux-mêmes. Le code attend pour obtenir des maisons parce que vous avez await avant. Il ne sait pas ce qui va se passer ensuite.

Ensuite, les deux méthodes qui nécessitent House s'exécuteront, mais la deuxième méthode (GetAppliancesForHouse) n'attendra pas que la première se termine avant de démarrer.

De même, le GetAppliancesForHouse n'aura pas sa propre compréhension s'il doit attendre ou non en fonction des dépendances. GetAppliancesForHouse ne s'exécutera pas, car votre code dit d'attendre GetFurnitureForHouse avant de commencer. Votre code s'exécutera toujours de manière séquentielle.

La compréhension de Jim est la suivante: nous ne devons attendre les deux méthodes que lorsqu'elles sont nécessaires. Pour qu'ils fonctionnent tous les deux parallèlement.

C'est généralement vrai. Comme d'autres l'ont souligné, le code peut toujours ne pas fonctionner en parallèle en fonction d'autres facteurs. De plus, il peut y avoir des raisons légitimes de ne pas vouloir exécuter du code en parallèle.

Il pense que si je le fais à ma façon, la deuxième méthode attendra la première, c'est-à-dire: GetAppliancesForHouse attendant GetFurnitureForHouse.

Il a raison.

Pour voir ce qui se passe exactement, vous pouvez mettre des points d'arrêt et voir ce qui se passe après chaque ligne. Dans le cas Jims, après être passé de Furniture à Appliances, la variable de meubles n'aura pas encore la valeur, c'est toujours une tâche, mais vous êtes déjà dans la ligne suivante.

Avec votre étui, en allant à la ligne Électroménagers, vous verrez que le Meuble a déjà de la valeur, puisqu'il l'a attendu.

49
Erndob

Aucun de vous n'est correct, voir la réponse par @ erndob pour les raisons. Cependant, une des questions reste sans réponse:

Quand faut-il attendre?

  • Voulez-vous que le travail soit effectué de manière séquentielle? Utilisez votre chemin.
  • Voulez-vous que le travail se fasse en parallèle? Utilisez la voie de Jim.

Remarque : La méthode de Jim ne s'exécutera pas en parallèle si le planificateur de tâches utilisé ne peut pas exécuter les deux tâches en même temps, par exemple, en raison d'un manque des ressources système (merci @ AdamSimon ).

8
SO used to be good