2
votes

Déclaration du type de retour de méthode Task sans mot clé async

Dans quelle situation retourneriez-vous une Tâche sans utiliser async dans la signature de la méthode?

J'ai une telle méthode dans le code ci-dessous mais j'ai du mal à comprendre ce qui se passe.

Pourquoi mon exemple de code ci-dessous ne s'exécute-t-il pas après l'une des instructions wait ? c'est à dire. pourquoi Console.WriteLine ("4)"); et Console.WriteLine ("3)"); et renvoient x; n'obtiennent jamais exécuté?

class Program
    {
        static void Main(string[] args)
        {
            TestAsync testAsync = new TestAsync();
            testAsync.Run();

            Console.Read();
        }
    }

    public class TestAsync
    {
        public async void Run()
        {
            Task<int> resultTask = GetInt();
            Console.WriteLine("2)");
            int x = await resultTask;
            Console.WriteLine("4)");
        }
        public async Task<int> GetInt()
        {
            Task<int> GetIntAfterLongWaitTask = GetIntAfterLongWait();
            Console.WriteLine("1)");
            int x = await GetIntAfterLongWaitTask;
            Console.WriteLine("3)");
            return x;
        }

        public Task<int> GetIntAfterLongWait()
        {            
            Task.Run(() =>
            {
                for (int i = 0; i < 500000000; i++)
                {
                    if (i % 10000000 == 0)
                    {
                        Console.WriteLine(i);
                    }
                }
            });

            Console.WriteLine("Returning 23");
            return new Task<int>(() => 23);
        }
    }

/*
Output is:
Returning 23
1)
2)
<list of ints>
*/


9 commentaires

Task est un type légitime qui peut être retourné par n'importe quelle méthode. S'il n'a pas le mot-clé async devant, vous ne pouvez simplement pas attendre quelque chose dans la méthode.


Mais alors pourquoi le compilateur ne donne-t-il pas un avertissement / une erreur de compilation?


Vous l'utilisez si votre méthode a juste besoin de renvoyer une tâche sans avoir besoin de l'attendre elle-même, par exemple car c'est la dernière instruction d'une méthode. Cela étant dit, vous ne devriez généralement jamais utiliser new Task . Si vous souhaitez renvoyer une valeur encapsulée en tant que tâche, c'est-à-dire un résultat de tâche terminé, utilisez Task.FromResult (23) qui présente l'avantage de ne pas utiliser un thread comme Task.Run et probablement nouvelle tâche .


@Backwards_Dave - Le compilateur ne donne pas d'avertissement ou d'erreur car c'est du code valide.


Je suis curieux de savoir où avez-vous utilisé le constructeur Task comme pratique?


La Tâche le constructeur n'a littéralement aucun cas d'utilisation .


@Enigmativity Je pensais que vous ne pouviez attendre qu'une méthode définie comme asynchrone, mais le compilateur ne se plaint pas si vous attendez une méthode qui n'est pas asynchrone mais renvoie une tâche. Vous pouvez donc attendre toute méthode marquée comme asynchrone ou non marquée comme asynchrone mais qui renvoie une tâche?


Vous ne pouvez attendre que des appels dans une méthode où cette méthode est marquée async . Cela n'a rien à voir avec la façon dont la méthode que vous appelez est marquée.


@Backwards_Dave - Lisez blogs.msdn.microsoft. com / pfxteam / 2011/01/13 / attendent-tout


3 Réponses :


0
votes

Vous créez probablement un nouveau thread dans la méthode GetIntAfterLongWait () . Essayez de changer return new Task (() => 23); en return Task.FromResult (23); .

Pour plus d'informations sur Task.FromResult , consultez la documentation MSDN (avec un bon exemple) sur Comment: créer des tâches pré-calculées


0 commentaires

5
votes

Lorsque vous renvoyez une Tâche à partir d'une méthode non asynchrone ?

Task est une promesse prononcée généralisée pour une valeur future . Que vous produisiez cette promesse à partir d'une méthode mot-clé async ou d'une autre source (comme un thread démarré ou des rappels IO) n'est pas d'intérêt pour l'appelant et seulement une stratégie d'implémentation. C'est aussi la raison pour laquelle les interfaces (ou la définition de méthode abstraite) n'ont pas du tout le mot-clé async ( async / await est une implémentation stratégie).

Votre exemple de code

  • Problème 1 : votre méthode GetIntAfterLongWait présente deux défauts. La première Task instanciée est instanciée et déchargée sur un thread, mais le résultat n'est jamais récupéré (donc jamais attendu ... et ne retarde jamais rien).
  • Problème 2 : la deuxième tâche (celle que vous renvoyez dans GetIntAfterLongWait ) est créée (par le constructeur avec une méthode à exécuter) mais pas démarrée ( Task.Start () ). D'autres méthodes plus simples sont les statiques Task.Run ou (dans ce cas) Task.FromResult . La tâche (ou la promesse) ne délivre jamais le résultat, car le bloc fonction du constructeur n'est jamais exécuté.
  • Problème 3 : la méthode Main n'attend pas le résultat de la tâche retournée (soit par wait soit par Task.Wait () ou Task.Result .

0 commentaires

1
votes

Le problème dans votre code est que vous n'êtes en fait wait jamais démarré de tâche puisque la méthode GetIntAfterLongWait renvoie une nouvelle instance de la tâche qui n'est pas démarrée. Donc, fondamentalement, vous êtes dans une impasse, attendant quelque chose qui ne démarre pas du tout.

Vous pouvez renvoyer Task.FromResult (23) qui est essentiellement une tâche déjà terminée, ou vous pouvez réellement exécuter votre tâche Task.Run (() => 23);


1 commentaires

Il n'est pas recommandé d'utiliser Task.Factory.StartNew ( docs.microsoft.com/en-us/dotnet/api/... ) sauf dans des cas particuliers dont ce cas ne fait pas partie leur.