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> */
3 Réponses :
Vous créez probablement un nouveau thread dans la méthode GetIntAfterLongWait ()
. Essayez de changer return new Task
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
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
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). 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é. Main
n'attend pas le résultat de la tâche retournée (soit par wait
soit par Task.Wait ()
ou Task.Result
. 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
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.
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 pasattendre
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é, utilisezTask.FromResult (23)
qui présente l'avantage de ne pas utiliser un thread commeTask.Run code> 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 code > 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éeasync
. 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