mot clé async (méthode asynchrone)
Le mot clé async est unique à C #. Java n'a rien de tel.
async est un mot-clé contextuel dans le monde C #. Il est automatiquement reconnu comme mot-clé par le compilateur uniquement lorsqu'il modifie une méthode, et peut être utilisé à d'autres fins telles que des noms de variables à d'autres endroits du code.
Le mot clé async permet de modifier deux types de méthodes: les expressions lambda ou les méthodes asynchrones.
Une méthode avec modification asynchrone est appelée méthode asynchrone, telle que:
public async Task<int> ExampleMethodAsync()
{
// (1) To do some code here synchronously...
await .....// (2) To do something asynchronously....
// (3) To do some code here after awiat code...
}
Tout comme la méthode ci-dessus ExampleMethodAsync (), grand-père Microsoft aime ajouter un suffixe Async après avoir défini le nom d'une fonction asynchrone (ce n'est pas nécessaire, l'ajout ou non d'un compilateur ne signalera pas une erreur ni n'affectera la fonctionnalité asynchrone), dites-nous Cette méthode est une méthode asynchrone. Lorsque nous définissons nous-mêmes des méthodes asynchrones, nous pouvons également copier cette habitude Microsoft. Dans la méthode modifiée
asynchrone , il devrait y avoir un mot-clé d' attente , et les deux mots-clés apparaissent généralement par paires. Bien sûr, si nous oublions accidentellement d'écrire une expression ou une instruction d' attente , cette méthode async s'exécute de manière synchrone par défaut. En même temps, le compilateur nous demandera si nous avons manqué attendre . De plus, dans la méthode async , il peut y avoir plusieurs instructions d' attente . Les instructions exécutées par
awiat sont généralement des tâches chronophages (c'est-à-dire certaines opérations qui bloqueront le thread principal, telles que l'obtention de réponses Http, l'écriture de documents, la sauvegarde de bases de données, etc.), sinon il n'y a pas besoin d'asynchronie.
Prenons l'exemple ci-dessus comme exemple (en supposant que l' attente dans l' exemple est la première attente ), le processus d'exécution de la méthode asynchrone (un aspect approximatif):
- Une fois que le thread principal entre dans la méthode ExampleMethodAsync (), il exécute (1) en premier; s'il existe une instruction pour créer Task ou Task <TResult> dans (1), ou appeler d'autres méthodes async (la valeur de retour est Task ou Task <TResult>) Pour la commodité de la description, nous l'appelons tous instruction de création de tâche; par exemple, créez une tâche ou une tâche <TResult> directement:
var tsk = Task.Run(()=>{
Thread.Sleep(1000);
Console.Writeline("Do another job asynchronously.");
});
Ou appelez une autre méthode asynchrone:
Task<string> getStringTask = client.GetStringAsync("https://docs.microsoft.com/dotnet");
Ensuite, la tâche asynchrone a déjà commencé à s'exécuter lorsque l'instruction de création de tâche est appelée (l'appel de l'instruction elle-même est dans le thread principal et la tâche interne est exécutée dans un nouveau thread), c'est-à-dire que le thread asynchrone a été démarré à ce moment , Comme il est démarré de manière asynchrone, il n'empêche pas le thread principal de continuer à descendre;
- Ensuite, le thread principal s'exécutera séquentiellement jusqu'à la première attente dans la méthode async. Si la première attente appelle une méthode async, alors le programme principal continue à entrer dans l'exécution de la méthode jusqu'à ce qu'il rencontre une tâche d'attente. Le thread sautera hors de la méthode ExampleMethodAsync; par exemple:
static void Main(string[] args)
{
// do something...
ExampleMethodAsync();
// do someting else...
}
public static async void ExampleMethodAsync()
{
// (1) 执行一些任务Do2Async()前准备的事情...
await Do2Async(); // (2)
// (3) 运行一些Do2Async()执行完之后的事情...
}
public static Task Do2Async()
{
// 执行一些t任务执行前的事情,比如任务的准备...
Task t = Task.Run(()=>{
// 异步任务中执行费时的事情...
});
// 运行一些与t无关的事情...
await t;
// 在这里执行一些t任务执行完相关的事情...
}
L'appelant (c'est-à-dire le thread principal où se trouve main) s'exécutera jusqu'à la ligne 20 avant de sauter hors de la méthode ExampleMethodAsync (), pas à la ligne 10.
- Le reste (3) de la méthode ExampleMethodAsync () est exécuté après l'exécution de la partie await (2).
- Supposons qu'il y ait un deuxième, troisième ... awiat dans ExampleMethodAsync (), car le programme principal a déjà sauté, et les attentes suivantes seront exécutées séquentiellement dans des threads asynchrones.
La méthode async peut avoir les trois types de retour suivants:
- Tâche
- Tâche <TResult>
- Le type de retour void est généralement utilisé dans les gestionnaires d'événements, ou dans les situations où vous n'avez besoin que de l'exécution de tâche et ne vous souciez pas des résultats de l'exécution de la tâche.
- Tout autre type avec la méthode GetAwaiter (depuis C # 7.0)
Notez que nous ne pouvons pas attendre (awiat) une méthode async void.
using System;
using System.Threading.Tasks;
using System.Threading;
namespace test
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine($"ThreadID:{Thread.CurrentThread.ManagedThreadId} Hello, I am Caller!");
DoAsync();
Console.WriteLine($"ThreadID:{Thread.CurrentThread.ManagedThreadId} Hello, I am Caller too!");
Console.Read();
}
public static async void DoAsync()
{
System.Console.WriteLine($"ThreadID:{Thread.CurrentThread.ManagedThreadId} In DoAsync(), before SunAsync()");
await SunAsync();
System.Console.WriteLine($"ThreadID:{Thread.CurrentThread.ManagedThreadId} After SunAsync(), DoAsync() End.");
}
public static async Task SunAsync()
{
var t = Task.Run(()=>{
System.Console.WriteLine($"ThreadID:{Thread.CurrentThread.ManagedThreadId} New Task~");
for(int i=0 ; i<10; i++)
{
Thread.Sleep(1000);
System.Console.WriteLine($"ThreadID:{Thread.CurrentThread.ManagedThreadId} I am playing game...");
}
});
System.Console.WriteLine($"ThreadID:{Thread.CurrentThread.ManagedThreadId} After Task, before await.");
await t;
System.Console.WriteLine($"ThreadID:{Thread.CurrentThread.ManagedThreadId} After await, before SunAsync() exit.");
}
}
}
Le résultat à ce moment:
ThreadID:1 Hello, I am Caller!
ThreadID:1 In DoAsync(), before SunAsync()
ThreadID:1 After Task, before await.
ThreadID:4 New Task~
ThreadID:4 I am playing game...
ThreadID:4 I am playing game...
ThreadID:4 I am playing game...
ThreadID:4 I am playing game...
ThreadID:4 I am playing game...
ThreadID:4 I am playing game...
ThreadID:4 I am playing game...
ThreadID:4 I am playing game...
ThreadID:4 I am playing game...
ThreadID:4 I am playing game...
ThreadID:1 After await, before SunAsync() exit.
ThreadID:1 After SunAsync(), DoAsync() End.
ThreadID:1 Hello, I am Caller too!
Lisez attentivement ce code et les résultats et réalisez que ce code est une méthode ansync void intégrée dans une méthode Ansync Task. Faites attention à l'expérience, cela ne signifie pas que la méthode DoAsync () est immédiatement quittée dès qu'elle rencontre le programme principal await (l'appelant de la méthode ansync), mais l'exécution atteint la ligne 33, et elle saute quand elle rencontre la première tâche. À partir du numéro ThreadID de sortie de cet exemple, on peut voir que le contenu après l'attente de 33 lignes est exécuté dans un nouveau thread (4 threads). Le contenu avant la ligne 33 wait s'exécute dans le thread principal (1 thread).
Si vous modifiez le code SunAsync () en (ajoutez un Thread.Sleep (150000) avant d'attendre):
public static async Task SunAsync()
{
var t = Task.Run(()=>{
System.Console.WriteLine($"ThreadID:{Thread.CurrentThread.ManagedThreadId} New Task~");
for(int i=0 ; i<10; i++)
{
Thread.Sleep(1000);
System.Console.WriteLine($"ThreadID:{Thread.CurrentThread.ManagedThreadId} I am playing game...");
}
});
System.Console.WriteLine($"ThreadID:{Thread.CurrentThread.ManagedThreadId} After Task, before await.");
Thread.Sleep(15000); //主线程睡15秒
await t;
System.Console.WriteLine($"ThreadID:{Thread.CurrentThread.ManagedThreadId} After await, before SunAsync() exit.");
}
ThreadID: 1 Bonjour, je suis un appelant!
ThreadID: 1 Dans DoAsync (), avant SunAsync ()
ThreadID: 1 Après la tâche, avant d'attente.
ThreadID: 4 New Task ~
ThreadID: 4 Je joue à un jeu…
ThreadID: 4 Je joue à un jeu…
ThreadID: 4 Je joue à un jeu…
ThreadID: 4 Je joue à un jeu…
ThreadID: 4 Je joue à un jeu…
ThreadID: 4 I je joue à un jeu…
ThreadID: 4 Je joue à un jeu…
ThreadID: 4 Je joue à un jeu…
ThreadID: 4 Je joue à un jeu…
ThreadID: 4 Je joue à un jeu…
ThreadID: 1 Après attente, avant la sortie de SunAsync ().
ThreadID: 1 Après SunAsync (), DoAsync () End.
ThreadID: 1 Bonjour, je suis aussi un appelant!
Parce que la tâche de Task.Run () se termine avant qu'elle ne s'exécute pour attendre, par conséquent, le contenu après await est toujours exécuté dans le thread principal (1 thread). Cet exemple nous dit que si la tâche a été exécutée avant l'attente, le contenu après l'attente sera toujours exécuté dans le thread d'origine.
En bref, l'appelant de la méthode async quitte le corps de la méthode async lorsqu'il rencontre une tâche d'attente réelle. Généralement, les choses qui n'ont rien à voir avec les tâches asynchrones sont traitées avant wait (cette partie du code est exécutée par le thread où se trouve l'appelant de la méthode asynchrone), et le code après await traite des choses après le traitement de la tâche asynchrone, donc cette partie du code peut être traitée Les choses liées aux tâches asynchrones (cette partie est généralement exécutée dans un thread asynchrone nouvellement créé, à moins que la tâche ne soit exécutée rapidement avant d'appeler wait, alors cette partie peut toujours être exécutée dans le thread appelant) .