3
votes

Marquer une fonction comme asynchrone mais pas d'appels d'attente, des problèmes?

Y a-t-il des effets secondaires à avoir une fonction marquée comme asynchrone, mais elle n'effectue aucun appel d'attente? Par exemple:

public interface IMyInterface
{
    Task DoSomethingAsync();
}

public class DoSomething1:IMyInterface
{
    public async Task DoSomethingAsync()
    {
        await getSomethingFromDatabaseAsync();
    }
}

public class DoSomething2:IMyInterface
{
    public async Task DoSomethingAsync()
    {
        doSomethingElse();
    }
}

IMyInterface est implémenté par un certain nombre de classes, mais pour l'une des classes, il n'y a pas d'appels d'attente . Cela posera-t-il des problèmes?


6 commentaires

Pourquoi le marquer comme asynchrone?


Parce que pour implémenter l'interface, la fonction doit avoir le mot Async à la fin, et je pense qu'il est déroutant d'avoir une méthode qui se termine par Async mais qui ne l'est pas. Je me demande si cela posera des problèmes.


Si c'était moi, je supprimerais simplement le suffixe Async () du nom de la méthode. Si la méthode n'est pas garantie d'être asynchrone, ce n'est peut-être pas approprié. Il suffit à l'appelant de savoir que la méthode renvoie une Task et qu'elle n'est pas terminée à moins que IsCompleted ne soit vrai.


N'utilisez pas async sur une méthode qui n'a pas de wait s. Le seul objectif de async < / code> est d'informer le compilateur que vous avez l'intention d'utiliser await . Si vous n'avez pas cette intention, ne marquez pas les méthodes comme asynchrones . Qu'il y ait ou non "des effets secondaires est totalement hors de propos . Que ce soit ou non cela "causera des problèmes" est non pertinent . Le async est là comme un marqueur qui attendent sera utilisé. Si vous êtes n'utilisez pas await , il n'y a généralement aucune raison de marquer une méthode comme async .


Je note que si vous faites cela, vous obtiendrez un avertissement du compilateur vous indiquant de ne pas faire cela . Faites attention aux avertissements du compilateur. Nous avons ajouté ces avertissements pour une raison . La raison en est que async ne doit être utilisé que pour indiquer que await est utilisé, donc s'il y a un async sans wait , quelqu'un fait quelque chose de mal .


Merci beaucoup Eric, je suppose que je cherche à comprendre la raison pour laquelle ces avertissements ont été ajoutés et quel effet cela aura sur mon application. Peut-être que vous considérez que cela n'est pas pertinent, mais je pense que c'est un peu injuste, je veux juste savoir pourquoi.


4 Réponses :


7
votes

Dans le cas où vous avez une méthode d'interface qui renvoie une tâche et que vous n'avez pas d'attente (ouais ça arrive). Supprimez simplement le mot-clé async et renvoyez Task.CompletedTask

La propriété Task.CompletedTask renvoie une tâche dont Status est défini sur RanToCompletion.

Obtient une tâche qui s'est déjà terminée avec succès.

public class DoSomething2:IMyInterface
{
    public Task DoSomethingAsync()
    {
        doSomethingElse();
        return Task.CompletedTask;
    }
}

Oui, il y a des effets secondaires, le compilateur est en train de mettre en place l'IAsyncStateMachine et produit un tas plus de IL , de plus les futurs développeurs examineront votre code avec ire . En ce qui concerne les autres différences fonctionnelles, je ne peux penser à aucune différence.


6 commentaires

C'est une bonne solution de contournement mais ne répond pas à ma question, sans cela, cela causera-t-il des problèmes?


@Rocklan vous n'avez pas besoin du mot-clé async , la seule raison pour laquelle ce mot-clé existe est que vous pouvez utiliser await . Si vous n'utilisez pas await , il n'y a aucune raison de le marquer async . C'est la bonne solution pour votre cas d'utilisation.


Merci, mais cela ne répond toujours pas à ma question.


@Rocklan Utiliser async quand vous n'attendez rien est inutile, c'est-à-dire que non, cela ne posera aucun problème. Je ne sais toujours pas pourquoi vous souhaitez ajouter async , votre interface ne l'applique pas


@ vasily.sib D'où tirez-vous cela? Ceci n'est pas la question


@JohanP désolé, mon erreur. Je viens de relire la question et je ne peux pas savoir d'où je viens :)



-2
votes

Dans votre cas, je pense qu'il pourrait y avoir un problème de blocage du thread principal (et cela dépend si vous vous en souciez ou non) et je pense que ce n'est pas un développeur veut.

Si vous n'avez pas d'appels en attente , vous pouvez faire ce qui suit pour que le thread principal ne soit pas bloqué (> .net 4.0):

public class DoSomething2:IMyInterface
{
     public async Task DoSomethingAsync()
     {
         await Task.Run(()=>doSomethingElse());
     }
}


0 commentaires

-3
votes

Les méthodes marquées comme asynchrones fonctionneront de la même manière qu'elles créeront juste un peu de surcharge, car lorsque la méthode est marquée comme async, le compilateur génère essentiellement une machine à états pour cette méthode. (qui dans votre cas ne sera pas utilisée dans certaines méthodes particulières) < / p>

https://foreverframe.net/what-lies-beneath- asyncawait-in-c /

https://msdn.microsoft.com/en-us/magazine /jj991977.aspx


0 commentaires

2
votes

IMyInterface est implémenté par pas mal de classes, mais pour l'une des classes, il n'y a pas d'appels d'attente. Cela posera-t-il des problèmes?

Je vais entrer en territoire dangereux ici et je ne suis pas d'accord avec Eric Lippert. Dans la grande majorité des cas, utiliser async sans await est en effet une erreur et l'avertissement du compilateur est utile. Je dirais que c'est vrai bien au nord de 90% du temps.

Cependant, je dirais que ce scénario est une exception à cette règle. Le problème avec la simple suppression de async / await est que les exceptions sont gérées différemment:

#pragma warning disable 1998
public async Task DoSomethingAsync()
#pragma warning restore 1998
{
  doSomethingElse();
}

// or

public Task DoSomethingAsync()
{
  try
  {
    doSomethingElse();
    return Task.CompletedTask;
  }
  catch (Exception ex)
  {
    return Task.FromException(ex);
  }
}

La sémantique attendue pour un La méthode de retour de Task consiste à capturer des exceptions et à les placer sur la Task renvoyée (enfin, au moins non- exceptions ). Pour conserver cette sémantique, vous devez soit utiliser async (et supprimer l'avertissement) ou un try / catch explicite:

XXX

3 commentaires

Merci beaucoup SC, et merci pour tous vos excellents articles sur async / await. Je les ai tous lus plusieurs fois :)


J'attendais que cette réponse se matérialise, c'est un excellent point sur l'exception que j'ai manquée. Vous retrouveriez-vous souvent à utiliser l'approche asynchrone ? Je suppose que cela ne commencerait à avoir du sens que lorsque l'efficacité n'était pas un gros problème, et qu'un gros bloc de capture ne convenait pas, même si même dans ce cas, j'ai tendance à être allergique à la désactivation


Historiquement, je me suis davantage rangé du côté d'Eric Lippert et j'ai vraiment évité l'approche async -with-pragma. Mais plus récemment, j'ai davantage utilisé cette technique, même en faisant une partie d'AsyncEx (pré-version) .