Il se peut que je manque quelque chose, mais quelle est la différence entre faire:
public void MyMethod()
{
Task t = Task.Factory.StartNew(DoSomethingThatTakesTime);
t.Wait();
UpdateLabelToSayItsComplete();
}
public async void MyMethod()
{
var result = Task.Factory.StartNew(DoSomethingThatTakesTime);
await result;
UpdateLabelToSayItsComplete();
}
private void DoSomethingThatTakesTime()
{
Thread.Sleep(10000);
}
Il se peut que je manque quelque chose
Tu es.
quelle est la différence entre faire
Task.Wait
etawait task
?
Vous commandez votre déjeuner du serveur au restaurant. Un moment après avoir donné votre commande, un ami entre et s'assoit à côté de vous et entame une conversation. Maintenant vous avez deux choix. Vous pouvez ignorer votre ami jusqu'à ce que la tâche soit terminée - vous pouvez attendre que votre soupe arrive et ne rien faire d'autre pendant que vous attendez. Ou vous pouvez répondre à votre ami, et lorsque votre ami cesse de parler, le serveur vous apportera votre soupe.
Task.Wait
bloque jusqu'à ce que la tâche soit terminée. Vous ignorez votre ami jusqu'à ce que la tâche soit terminée. await
continue de traiter les messages dans la file d'attente des messages et, une fois la tâche terminée, il met en file d'attente un message qui indique "reprendre là où vous l'avez laissé après cette attente". Vous parlez à votre ami et quand il y a une pause dans la conversation, la soupe arrive.
Pour démontrer la réponse d'Eric, voici un code:
public void ButtonClick(object sender, EventArgs e)
{
Task t = new Task.Factory.StartNew(DoSomethingThatTakesTime);
t.Wait();
//If you press Button2 now you won't see anything in the console
//until this task is complete and then the label will be updated!
UpdateLabelToSayItsComplete();
}
public async void ButtonClick(object sender, EventArgs e)
{
var result = Task.Factory.StartNew(DoSomethingThatTakesTime);
await result;
//If you press Button2 now you will see stuff in the console and
//when the long method returns it will update the label!
UpdateLabelToSayItsComplete();
}
public void Button_2_Click(object sender, EventArgs e)
{
Console.WriteLine("Button 2 Clicked");
}
private void DoSomethingThatTakesTime()
{
Thread.Sleep(10000);
}
Cet exemple montre très clairement la différence. Avec async/wait, le thread appelant ne se bloque pas et ne continue pas son exécution.
static void Main(string[] args)
{
WriteOutput("Program Begin");
// DoAsTask();
DoAsAsync();
WriteOutput("Program End");
Console.ReadLine();
}
static void DoAsTask()
{
WriteOutput("1 - Starting");
var t = Task.Factory.StartNew<int>(DoSomethingThatTakesTime);
WriteOutput("2 - Task started");
t.Wait();
WriteOutput("3 - Task completed with result: " + t.Result);
}
static async Task DoAsAsync()
{
WriteOutput("1 - Starting");
var t = Task.Factory.StartNew<int>(DoSomethingThatTakesTime);
WriteOutput("2 - Task started");
var result = await t;
WriteOutput("3 - Task completed with result: " + result);
}
static int DoSomethingThatTakesTime()
{
WriteOutput("A - Started something");
Thread.Sleep(1000);
WriteOutput("B - Completed something");
return 123;
}
static void WriteOutput(string message)
{
Console.WriteLine("[{0}] {1}", Thread.CurrentThread.ManagedThreadId, message);
}
Sortie DoAsTask:
[1] Début du programme [1] 1 - Démarrer [1] 2 - Tâche démarrée [3] A - Commencer quelque chose [3] B - Quelque chose est terminé [1] 3 - Tâche terminée avec résultat: 123 [1] Fin du programme
Sortie DoAsAsync:
[1] Début du programme [1] 1 - Démarrer [1] 2 - Tâche démarrée [3] A - Commencer quelque chose [1] Fin du programme [3] B - Complété quelque chose [3] 3 - Tâche terminée avec résultat: 123
Mise à jour: exemple amélioré en affichant l'ID du thread dans la sortie.
Wait (), fera exécuter le code potentiellement asynchrone de manière synchrone. attendre ne sera pas.
Par exemple, vous avez une application Web asp.net. UserA appelle/getUser/1 point de terminaison. asp.net app pool choisira un thread dans le pool de threads (Thread1) et ce thread effectuera un appel http. Si vous attendez (), ce fil sera bloqué jusqu'à la résolution de l'appel http. Pendant qu'il attend, si UserB appelle/getUser/2, le pool d'applications devra servir un autre thread (Thread2) pour effectuer à nouveau un appel http. Vous venez de créer (en fait, à partir du pool d'applications) un autre thread sans aucune raison, car vous ne pouvez pas utiliser Thread1, il a été bloqué par Wait ().
Si vous utilisez wait sur Thread1, SyncContext gérera la synchronisation entre Thread1 et les appels http. Simplement, il notifiera une fois que l'appel http est terminé. En attendant, si UserB appelle/getUser/2, vous utiliserez à nouveau Thread1 pour établir un appel http, car il a été publié une fois que l'attente a été touchée. Ensuite, une autre demande peut l'utiliser, et même plus. Une fois l'appel http terminé (utilisateur1 ou utilisateur2), Thread1 peut obtenir le résultat et revenir à l'appelant (client). Thread1 a été utilisé pour plusieurs tâches.
Dans cet exemple, pas grand chose, pratiquement. Si vous attendez une tâche qui retourne sur un autre thread (comme un appel WCF) ou abandonne le contrôle au système d'exploitation (comme File IO), wait utilisera moins de ressources système en ne bloquant pas un thread.
Dans l'exemple ci-dessus, vous pouvez utiliser "TaskCreationOptions.HideScheduler" et modifier considérablement la méthode "DoAsTask". La méthode elle-même n'est pas asynchrone, comme c'est le cas avec "DoAsAsync", car elle renvoie une valeur "Task" et est marquée comme "async", ce qui permet de combiner plusieurs combinaisons. C'est ainsi qu'elle me donne exactement la même chose que d'utiliser "async/wait" :
static Task DoAsTask()
{
WriteOutput("1 - Starting");
var t = Task.Factory.StartNew<int>(DoSomethingThatTakesTime, TaskCreationOptions.HideScheduler); //<-- HideScheduler do the magic
TaskCompletionSource<int> tsc = new TaskCompletionSource<int>();
t.ContinueWith(tsk => tsc.TrySetResult(tsk.Result)); //<-- Set the result to the created Task
WriteOutput("2 - Task started");
tsc.Task.ContinueWith(tsk => WriteOutput("3 - Task completed with result: " + tsk.Result)); //<-- Complete the Task
return tsc.Task;
}