ejemplos ejemplo await async c# async-await c#-5.0

async await c# ejemplos



¿Cómo se crea un método asíncrono en C#? (3)

Cada publicación de blog que he leído te dice cómo consumir un método asíncrono en C #, pero por alguna extraña razón nunca expliques cómo construir tus propios métodos asíncronos para consumir. Así que ahora tengo este código que consume mi método:

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

Y escribí este método que es CountToAsync :

private Task<DateTime> CountToAsync(int num = 1000) { return Task.Factory.StartNew(() => { for (int i = 0; i < num; i++) { Console.WriteLine("#{0}", i); } }).ContinueWith(x => DateTime.Now); }

¿Es esto, el uso de Task.Factory , la mejor manera de escribir un método asincrónico, o debería escribir esto de otra manera?


No recomiendo StartNew menos que necesite ese nivel de complejidad.

Si su método asincrónico depende de otros métodos de sincronización, el enfoque más fácil es utilizar la palabra clave async :

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

Si su método async está haciendo un trabajo de CPU, debe usar Task.Run :

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

Puede encontrar útil mi introducción async / await .


Si no desea utilizar async / await dentro de su método, pero aún así "decorarlo" para poder usar la palabra clave TaskCompletionSource.cs desde afuera, TaskCompletionSource.cs :

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

Desde aquí y here

Para respaldar dicho paradigma con Tareas, necesitamos una forma de conservar la fachada de la tarea y la capacidad de referirnos a una operación asincrónica arbitraria como una Tarea, pero para controlar el tiempo de vida de esa Tarea de acuerdo con las reglas de la infraestructura subyacente que proporciona el asincronía, y hacerlo de una manera que no cueste significativamente. Este es el objetivo de TaskCompletionSource.

Vi también se utiliza en la fuente de .NET, por ejemplo. WebClient.cs :

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

Finalmente, encontré útil también lo siguiente:

Me hacen esta pregunta todo el tiempo. La implicación es que debe haber algún hilo en alguna parte que bloquee la llamada de E / S al recurso externo. Entonces, el código asíncrono libera el hilo de solicitud, pero solo a expensas de otro hilo en otra parte del sistema, ¿verdad? No, en absoluto. Para entender por qué las solicitudes asíncronas escalan, rastrearé un ejemplo (simplificado) de una llamada de E / S asíncrona. Digamos que una solicitud necesita escribir en un archivo. El hilo de solicitud llama al método de escritura asíncrona. WriteAsync es implementado por la Base Class Library (BCL) y utiliza los puertos de terminación para su E / S asíncrona. Por lo tanto, la llamada WriteAsync se pasa al sistema operativo como una escritura de archivo asincrónico. Luego, el sistema operativo se comunica con la pila de controladores, pasando los datos para escribir en un paquete de solicitud de E / S (IRP). Aquí es donde las cosas se ponen interesantes: si un controlador de dispositivo no puede manejar un IRP inmediatamente, debe manejarlo de manera asincrónica. Entonces, el controlador le dice al disco que comience a escribir y devuelve una respuesta "pendiente" al sistema operativo. El sistema operativo pasa esa respuesta "pendiente" al BCL y el BCL devuelve una tarea incompleta al código de manejo de solicitud. El código de manejo de solicitudes espera a la tarea, que devuelve una tarea incompleta de ese método, y así sucesivamente. Finalmente, el código de manejo de solicitudes termina devolviendo una tarea incompleta a ASP.NET, y el hilo de solicitud se libera para regresar al grupo de subprocesos.

Introducción a Async / Await en ASP.NET

Si el objetivo es mejorar la escalabilidad (en lugar de la capacidad de respuesta), todo depende de la existencia de una E / S externa que brinde la oportunidad de hacerlo.


Solo agregue un par de palabras a su código - "async" y "await":

private async Task<DateTime> CountToAsync(int num = 1000) { return await Task.Factory.StartNew(() => { for (int i = 0; i < num; i++) { Console.WriteLine("#{0}", i); } }).ContinueWith(x => DateTime.Now); }