584 votes

async / await - quand renvoyer une tâche vs void?

Dans quels scénarios voudrait-on utiliser

 public async Task AsyncMethod(int num)
 

au lieu de

 public async void AsyncMethod(int num)
 

Le seul scénario auquel je peux penser est si vous avez besoin de la tâche pour pouvoir suivre ses progrès.

De plus, dans la méthode suivante, les mots-clés async et await sont-ils inutiles?

   public static async void AsyncMethod2(int num)
    {
        await Task.Factory.StartNew(() => Thread.Sleep(num));
    }
 

484voto

hvd Points 42125

1) Normalement, vous souhaitez retourner un Task. La principale exception doit être quand vous avez besoin d'avoir un void type de retour (pour les événements). Si il n'y a pas de raison de refuser d'avoir l'appelant await votre tâche, pourquoi refuser?

2) async des méthodes qui renvoient void sont spéciale d'un autre aspect: ils représentent de haut niveau des opérations asynchrones, et ont des règles supplémentaires qui entrent en jeu lors de votre tâche renvoie une exception. La façon la plus simple est de montrer la différence est avec un exemple:

static async void f()
{
    await h();
}

static async Task g()
{
    await h();
}

static async Task h()
{
    throw new NotImplementedException();
}

private void button1_Click(object sender, EventArgs e)
{
    f();
}

private void button2_Click(object sender, EventArgs e)
{
    g();
}

private void button3_Click(object sender, EventArgs e)
{
    GC.Collect();
}

fs'exception est toujours "observé". Une exception qui laisse un haut niveau de méthode asynchrone est simplement traité comme n'importe quel autre exception non gérée. gs'exception n'est jamais observée. Lorsque le garbage collector vient de nettoyer la tâche, il voit que la tâche a entraîné dans une exception, et personne ne gérée à l'exception. Lorsque cela se produit, TaskScheduler.UnobservedTaskException gestionnaire s'exécute. Vous ne devez jamais laisser cela se produire. Pour utiliser votre exemple,

public static async void AsyncMethod2(int num)
{
    await Task.Factory.StartNew(() => Thread.Sleep(num));
}

Oui, utilisez async et await d'ici, ils assurez-vous que votre méthode fonctionne toujours correctement si une exception est levée.

pour plus d'informations, voir: http://msdn.microsoft.com/en-us/magazine/jj991977.aspx

50voto

Davide Icardi Points 2215

Je suis venu dans ce très utile article sur async et void écrit par Jérôme Laban: http://www.jaylee.org/post/2012/07/08/c-sharp-async-tips-and-tricks-part-2-async-void.aspx

La ligne de fond est que l' async+void peut faire planter le système et devrait normalement être utilisé uniquement sur l'INTERFACE utilisateur côté des gestionnaires d'événements.

La raison derrière cela est le Contexte de Synchronisation utilisé par le AsyncVoidMethodBuilder, être pas dans cet exemple. Quand il n'y a pas de ambiante Contexte de Synchronisation, aucune exception n'est pas gérée par le corps d'un async void méthode est renvoyé sur le pool de threads. Alors que il n'y a apparemment pas d'autre endroit logique où ce genre de non gérée exception peut être levée, l'inconvénient est que le processus a été arrêté, parce que les exceptions non gérées sur le pool de threads effectivement résilier le processus depuis .NET 2.0. Vous pouvez intercepter toute exception non gérée à l'aide de l'AppDomain.UnhandledException événement, mais il n'y a aucun moyen de récupérer le processus de cet événement.

Lors de l'écriture de l'INTERFACE utilisateur des gestionnaires d'événements, async void méthodes sont en quelque sorte indolore, car les exceptions sont traitées de la même façon trouvés dans non méthodes asynchrones; ils sont jetés sur le Répartiteur. Il y a un possibilité de le récupérer à partir de ces exceptions, avec plus que correcte pour la plupart des cas. En dehors de l'INTERFACE utilisateur, les gestionnaires d'événements toutefois, async void des méthodes sont en quelque sorte dangereux à l'usage et ne peut pas faciles à trouver.

0voto

Billdr Points 913

Je suppose que vous utilisez Metro (er, Windows Store Application). Vous souhaitez renvoyer une tâche lorsque vous utilisez la méthode pour attribuer une valeur à une variable. Alors

 int myValue = AsyncMethod(4);
 

myValue n'aura pas de valeur tant que le thread ne sera pas retourné, ce qui peut poser problème, en fonction de la structure de votre code.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X