web-dev-qa-db-fra.com

Comprendre asynchrone / attendre en C #

Je commence à en savoir plus sur async/wait en C # 5.0, et je ne le comprends pas du tout. Je ne comprends pas comment il peut être utilisé pour le parallélisme. J'ai essayé le programme très basique suivant:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Task task1 = Task1();
            Task task2 = Task2();

            Task.WaitAll(task1, task2);

            Debug.WriteLine("Finished main method");
        }

        public static async Task Task1()
        {
            await new Task(() => Thread.Sleep(TimeSpan.FromSeconds(5)));
            Debug.WriteLine("Finished Task1");
        }

        public static async Task Task2()
        {
            await new Task(() => Thread.Sleep(TimeSpan.FromSeconds(10)));
            Debug.WriteLine("Finished Task2");
        }

    }
}

Ce programme bloque simplement l'appel à Task.WaitAll() et ne se termine jamais, mais je ne comprends pas pourquoi. Je suis sûr que je manque quelque chose de simple ou que je n'ai tout simplement pas le bon modèle mental de cela, et aucun des blogs ou articles MSDN qui existent ne sont utiles.

66
Alex Marshall

Je vous recommande de commencer avec mon introduction à async/await et de suivre avec documentation MSDN officielle sur TAP .

Comme je le mentionne dans mon billet de blog d'introduction, il y a plusieurs membres Task qui sont des restes du TPL et n'ont aucune utilité dans le code pur async. new Task et Task.Start doit être remplacé par Task.Run (ou TaskFactory.StartNew). De même, Thread.Sleep doit être remplacé par Task.Delay.

Enfin, je vous recommande de ne pas utiliser Task.WaitAll; votre application Console doit simplement Wait sur un seul Task qui utilise Task.WhenAll. Avec toutes ces modifications, votre code ressemblerait à:

class Program
{
    static void Main(string[] args)
    {
        MainAsync().Wait();
    }

    public static async Task MainAsync()
    {
        Task task1 = Task1();
        Task task2 = Task2();

        await Task.WhenAll(task1, task2);

        Debug.WriteLine("Finished main method");
    }

    public static async Task Task1()
    {
        await Task.Delay(5000);
        Debug.WriteLine("Finished Task1");
    }

    public static async Task Task2()
    {
        await Task.Delay(10000);
        Debug.WriteLine("Finished Task2");
    }
}
63
Stephen Cleary

Comprendre la tâche C #, asynchroniser et attendre

Tâche C #

La classe de tâches est un wrapper de tâches asynchrone. Thread.Sleep (1000) peut arrêter l'exécution d'un thread pendant 1 seconde. Tandis que Task.Delay (1000) n'arrêtera pas le travail en cours. Voir le code:

public static void Main(string[] args){
    TaskTest();
}
private static void TaskTest(){
     Task.Delay(5000);
     System.Console.WriteLine("task done");
}

Lors de l'exécution, "tâche terminée" apparaîtra immédiatement. Je peux donc supposer que chaque méthode de Task doit être asynchrone. Si je remplace TaskTest () par Task.Run (() => TaskTest ()), la tâche effectuée n'apparaîtra pas du tout tant que je n'ajoute pas Console.ReadLine (); après la méthode Run.

En interne, la classe Task représente un état de thread dans une machine d'état. Chaque état dans la machine d'état a plusieurs états tels que Démarrer, Délai, Annuler et Arrêter.

asynchroniser et attendre

Maintenant, vous vous demandez peut-être si toutes les tâches sont asynchrones, quel est l'objectif de Task.Delay? ensuite, retardons vraiment le fil d'exécution en utilisant async et attendons

public static void Main(string[] args){
     TaskTest();
     System.Console.WriteLine("main thread is not blocked");
     Console.ReadLine();
}
private static async void TaskTest(){
     await Task.Delay(5000);
     System.Console.WriteLine("task done");
}

dire à l'appelant asynchrone, je suis une méthode asynchrone, n'attendez pas pour moi. attendre à l'intérieur du TaskTest () demander d'attendre la tâche asynchrone. Maintenant, après avoir exécuté, le programme attendra 5 secondes pour afficher le texte de la tâche effectuée.

Annuler une tâche

Étant donné que la tâche est une machine d'état, il doit y avoir un moyen d'annuler la tâche pendant qu'elle est en cours d'exécution.

static CancellationTokenSource tokenSource = new CancellationTokenSource();
public static void Main(string[] args){
    TaskTest();
    System.Console.WriteLine("main thread is not blocked");
    var input=Console.ReadLine();
    if(input=="stop"){
          tokenSource.Cancel();
          System.Console.WriteLine("task stopped");
     }
     Console.ReadLine();
}
private static async void TaskTest(){
     try{
          await Task.Delay(5000,tokenSource.Token);
     }catch(TaskCanceledException e){
          //cancel task will throw out a exception, just catch it, do nothing.
     }
     System.Console.WriteLine("task done");
}

Maintenant, lorsque le programme est en cours d'exécution, vous pouvez entrer "stop" pour annuler la tâche de retard.

13
Andrew Zhu

Vos tâches ne se terminent jamais car elles ne démarrent jamais.

Je voudrais Task.Factory.StartNew pour créer une tâche et la démarrer.

public static async Task Task1()
{
  await Task.Factory.StartNew(() => Thread.Sleep(TimeSpan.FromSeconds(5)));
  Debug.WriteLine("Finished Task1");
}

public static async Task Task2()
{
  await Task.Factory.StartNew(() => Thread.Sleep(TimeSpan.FromSeconds(10)));
  Debug.WriteLine("Finished Task2");
}

En remarque, si vous essayez vraiment de faire une pause dans une méthode asynchrone, il n'est pas nécessaire de bloquer un thread entier, utilisez simplement Task.Delay

public static async Task Task1()
{
  await Task.Delay(TimeSpan.FromSeconds(5));
  Debug.WriteLine("Finished Task1");
}

public static async Task Task2()
{
  await Task.Delay(TimeSpan.FromSeconds(10));
  Debug.WriteLine("Finished Task2");
}
11
MerickOWA

Async et wait sont des marqueurs qui marquent les positions de code à partir desquelles le contrôle doit reprendre une fois la tâche (thread) terminée. Voici une vidéo YouTube détaillée qui explique le concept de manière démonstrative http://www.youtube.com/watch?v=V2sMXJnDEjM

Si vous le souhaitez, vous pouvez également lire cet article de coodeproject qui explique la même chose de manière plus visuelle. http://www.codeproject.com/Articles/599756/Five-Great-NET-Framework-4-5-Features#Feature1:- "Async" et "Await" (Marques de code)

7
Shivprasad Koirala