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.
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");
}
}
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.
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.
É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.
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");
}
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)