Comment créez-vous une méthode asynchrone en C #?

Chaque article de blog que j’ai lu vous indique comment utiliser une méthode asynchrone en C #, mais pour une raison quelconque, n’expliquez jamais comment créer vos propres méthodes asynchrones à consumr. J’ai donc ce code en ce moment qui utilise ma méthode:

private async void button1_Click(object sender, EventArgs e) { var now = await CountToAsync(1000); label1.Text = now.ToSsortingng(); } 

Et j’ai écrit cette méthode qui est CountToAsync :

 private Task CountToAsync(int num = 1000) { return Task.Factory.StartNew(() => { for (int i = 0; i  DateTime.Now); } 

Est-ce l’utilisation de Task.Factory , la meilleure façon d’écrire une méthode asynchrone, ou devrais-je écrire cela d’une autre manière?

Je ne recommande pas StartNew sauf si vous avez besoin de ce niveau de complexité.

Si votre méthode asynchrone dépend d’autres méthodes asynchrones, l’approche la plus simple consiste à utiliser le mot clé async :

 private static async Task CountToAsync(int num = 10) { for (int i = 0; i < num; i++) { await Task.Delay(TimeSpan.FromSeconds(1)); } return DateTime.Now; } 

Si votre méthode asynchrone fait le travail du processeur, vous devez utiliser Task.Run :

 private static async Task CountToAsync(int num = 10) { await Task.Run(() => ...); return DateTime.Now; } 

Vous pouvez trouver mon async / await intro utile.

Si vous ne voulez pas utiliser async / waiting dans votre méthode, mais quand même “décorez-le” de façon à pouvoir utiliser le mot clé wait de l’extérieur, TaskCompletionSource.cs :

 public static Task RunAsync(Func function) { if (function == null) throw new ArgumentNullException(“function”); var tcs = new TaskCompletionSource(); ThreadPool.QueueUserWorkItem(_ => { try { T result = function(); tcs.SetResult(result); } catch(Exception exc) { tcs.SetException(exc); } }); return tcs.Task; } 

D’ici et ici

Pour supporter un tel paradigme avec Tasks, nous avons besoin d’un moyen de conserver la façade de la tâche et de faire référence à une opération asynchrone arbitraire en tant que tâche, mais de contrôler la durée de vie de la tâche en fonction des règles de l’infrastructure sous-jacente. asynchronie, et de le faire d’une manière qui ne coûte pas cher. C’est le but de TaskCompletionSource.

J’ai vu est également utilisé dans la source .NET par exemple. WebClient.cs :

  [HostProtection(ExternalThreading = true)] [ComVisible(false)] public Task UploadSsortingngTaskAsync(Uri address, ssortingng method, ssortingng data) { // Create the task to be returned var tcs = new TaskCompletionSource(address); // Setup the callback event handler UploadSsortingngCompletedEventHandler handler = null; handler = (sender, e) => HandleCompletion(tcs, e, (args) => args.Result, handler, (webClient, completion) => webClient.UploadSsortingngCompleted -= completion); this.UploadSsortingngCompleted += handler; // Start the async operation. try { this.UploadSsortingngAsync(address, method, data, tcs); } catch { this.UploadSsortingngCompleted -= handler; throw; } // Return the task that represents the async operation return tcs.Task; } 

Enfin, j’ai trouvé utile aussi les suivants:

On me pose cette question tout le temps. L’implication est qu’il doit y avoir un thread quelque part qui bloque l’appel d’E / S à la ressource externe. Ainsi, le code asynchrone libère le thread de demande, mais seulement au désortingment d’un autre thread ailleurs dans le système, non? Non pas du tout. Pour comprendre pourquoi les requêtes asynchrones évoluent, je vais suivre un exemple (simplifié) d’un appel d’E / S asynchrone. Disons qu’une requête doit écrire dans un fichier. Le thread de demande appelle la méthode d’écriture asynchrone. WriteAsync est implémenté par la BCL (Base Class Library) et utilise des ports d’achèvement pour ses E / S asynchrones. Ainsi, l’appel WriteAsync est transmis au système d’exploitation sous forme d’écriture de fichier asynchrone. Le système d’exploitation communique ensuite avec la stack de pilotes, transmettant les données pour écrire dans un paquet de demande d’E / S (IRP). C’est là que les choses deviennent intéressantes: si un pilote de périphérique ne peut pas gérer un IRP immédiatement, il doit le gérer de manière asynchrone. Ainsi, le pilote demande au disque de commencer à écrire et renvoie une réponse «en attente» au système d’exploitation. Le système d’exploitation transmet cette réponse «en attente» à la BCL et la BCL renvoie une tâche incomplète au code de traitement des demandes. Le code de traitement des demandes attend la tâche, qui renvoie une tâche incomplète de cette méthode, etc. Enfin, le code de gestion des requêtes renvoie une tâche incomplète à ASP.NET et le thread de demande est libéré pour retourner au pool de threads.

Introduction à Async / Await sur ASP.NET

Si l’objective est d’améliorer l’évolutivité (plutôt que la réactivité), tout repose sur l’existence d’une E / S externe qui offre la possibilité de le faire.