web-dev-qa-db-fra.com

Task.Delay () ne se comporte pas comme prévu

Task.Delay () ne se comporte pas comme prévu ou plutôt je ne comprends pas ce qu'il est censé faire. J'essaie de comprendre Tasks en C # et comment remplacer Threads dans mon implémentation.

Ce que j'essaie de faire, c'est quelque chose comme ceci:

  • Bien que vrai
    • imprimer une ligne
    • attendez une seconde,
    • Si la condition est satisfaite, quittez la boucle, sinon continuez à boucler

Je l'ai bien implémenté avec Threads, mais tous les enfants sympas disent que je devrais utiliser Task, et ne touchez pas Thread.

Donc, pour le code, j'ai ceci (Ignorer [Test] - c'est juste un moyen pratique d'essayer les choses)

    [Test]
    public void ChattyTask()
    {
        var chattyTask = new Task(ChattyWriter);
        chattyTask.Start();
        chattyTask.Wait();
    }

    public void ChattyWriter()
    {
        int count = 0;
        while (true)
        {
            var message = String.Format("Chatty Writer number {0}", count);
            Trace.WriteLine(message);
            count++;
            Task.Delay(1000);

            if (count >= 20)
            {
                break;
            }
        }
    }

Lorsque je lance ceci, le test se termine en millisecondes, pas en 20 secondes comme je m'y attendais. Si je remplace Task.Delay() par Thread.Sleep(), tout fonctionne comme prévu et j'obtiens l'impression une fois par seconde. J'ai essayé d'ajouter async et await dans ChattyWriter(), mais non seulement il n'ajoutait pas de délai d'une seconde, mais il n'imprimait qu'une seule ligne au lieu de 20.

Qu'est-ce que je fais mal?

Cela va probablement aider à décrire ce que je fais: mon projet fonctionne avec une API externe (RESTful) et après avoir demandé que certaines tâches se produisent, je dois interroger l'API pour vérifier si la tâche est terminée. Les tâches externes peuvent durer longtemps: 1 à 15 minutes. J'ai donc besoin d'un certain délai entre la vérification de l'achèvement. Et il pourrait y avoir de nombreux processus simultanés différents exécutés avec plusieurs tâches externes. Je comprends que si j'utilise Thread.Sleep() lors de l'interrogation, d'autres processus sur le même Thread seront bloqués sans raison valable.

20
trailmax

Task.Delay renvoie un objet Task sur lequel vous devez attendre. Sinon, le code suivant sera exécuté immédiatement. Par conséquent, vous devez déclarer votre méthode comme async. Ensuite, vous pouvez attendre Task.Delay

public async Task ChattyWriter()
{
    int count = 0;
    while (true)
    {
        var message = String.Format("Chatty Writer number {0}", count);
        Trace.WriteLine(message);
        count++;
        await Task.Delay(1000);
           ...
    }
}

Vous devez interrompre votre fil d'appel d'une manière ou d'une autre. Le test unitaire se terminerait ainsi que le thread d'arrière-plan. Mais si vous appelez cette méthode à partir de l'interface utilisateur, l'interface utilisateur ne sera pas bloquée.

En appelant Wait sur une méthode asynchrone, vous vous retrouverez avec un blocage. Voir ici pour plus d'informations.

33
slfan

Task.Delay(1000); crée une tâche asynchrone qui se terminera après une seconde, mais l'exécution de la méthode actuelle se poursuivra en parallèle.

Pour attendre la fin de la tâche, vous pouvez remplacer

Task.Delay(1000);

avec

Task.Delay(1000).Wait();
21
Cristian Lupascu

Task.Delay () crée en fait une tâche, il vous suffit donc de l'attendre.

Essaye ça

        public static void ChattyWriter()
    {
        int count = 0;
        while (true)
        {
            var message = String.Format("Chatty Writer number {0}", count);
            Console.WriteLine(message);
            count++;
            var t = Task.Delay(1000);
            t.Wait();

            if (count >= 20)
            {
                break;
            }
        }
    }
1
Pandacoon