without whenall method httpresponsemessage explained ejemplo create await async c# async-await

whenall - task httpresponsemessage c#



¿Cómo escribir un método "a la espera"? (5)

¿Cómo escribiría mi propio método "a la espera"? ¿Es tan simple como envolver el código que quiero ejecutar de forma asíncrona en una Task y devolver eso?

Esa es una opción, pero lo más probable es que no sea lo que quiere hacer, porque en realidad no le ofrece muchas de las ventajas del código asíncrono. Para obtener más detalles, consulte ¿Debería exponer las envolturas asincrónicas de Stephen Toub para métodos síncronos?

En general, los métodos no son esperables, los tipos son. Si desea poder escribir algo como await MyMethod() , MyMethod() debe devolver Task , Task<T> o un tipo de await personalizado. Usar un tipo personalizado es un escenario raro y avanzado; usando Task , tienes varias opciones:

  • Escribe tu método usando async y await . Esto es útil para componer acciones de forma asincrónica, pero no se puede usar para las llamadas en await más internas.
  • Cree la Task usando uno de los métodos en Task , como Task.Run() o Task.FromAsync() .
  • Use TaskCompletionSource . Este es el enfoque más general, se puede usar para crear métodos de await de todo lo que sucederá en el futuro.

Finalmente estoy investigando las palabras clave async & await, que como que "entiendo", pero todos los ejemplos que he visto llaman a los métodos asincrónicos en .Net Framework, por ejemplo, este , que llama a HttpClient.GetStringAsync() .

Lo que no tengo tan claro es qué sucede con un método así, y cómo escribiría mi propio método "a la espera". ¿Es tan simple como envolver el código que quiero ejecutar de forma asíncrona en una tarea y devolver eso?


... cómo escribiría mi propio método "a la espera".

Devolver una Task no es la única forma. Tienes una opción para crear un awaiter personalizado (implementando GetAwaiter e INotifyCompletion ), aquí hay una gran lectura: "Espere cualquier cosa" . Ejemplos de API .NET que devuelven servidores personalizados: Task.Yield() , Dispatcher.InvokeAsync .

Tengo algunas publicaciones con esperadores personalizados here y here , por ejemplo:

// don''t use this in production public static class SwitchContext { public static Awaiter Yield() { return new Awaiter(); } public struct Awaiter : System.Runtime.CompilerServices.INotifyCompletion { public Awaiter GetAwaiter() { return this; } public bool IsCompleted { get { return false; } } public void OnCompleted(Action continuation) { ThreadPool.QueueUserWorkItem((state) => ((Action)state)(), continuation); } public void GetResult() { } } } // ... await SwitchContext.Yield();


Es tan simple como

Task.Run(() => ExpensiveTask());

Para que sea un método a la espera:

public Task ExpensiveTaskAsync() { return Task.Run(() => ExpensiveTask()); }

Lo importante aquí es devolver una tarea. El método ni siquiera tiene que marcarse como sincronización. (Solo lea un poco más para que aparezca en la imagen)

Ahora esto se puede llamar como

async public void DoStuff() { PrepareExpensiveTask(); await ExpensiveTaskAsync(); UseResultsOfExpensiveTask(); }

Tenga en cuenta que aquí la firma del método dice async , ya que el método puede devolver el control al llamador hasta que vuelva a aparecer ExpensiveTaskAsync() . Además, costoso en este caso significa mucho tiempo, como una solicitud web o similar. Para enviar cálculos pesados ​​a otro hilo, generalmente es mejor usar los enfoques "antiguos", es decir, System.ComponentModel.BackgroundWorker para aplicaciones GUI o System.Threading.Thread .



Simplemente convierta su método en Tarea. como @Romiox Yo suelo usar esta extensión

public static partial class Ext { #region Public Methods public static Task ToTask(Action action) { return Task.Run(action); } public static Task<T> ToTask<T>(Func<T> function) { return Task.Run(function); } public static async Task ToTaskAsync(Action action) { await Task.Run(action); } public static async Task<T> ToTaskAsync<T>(Func<T> function) { return await Task.Run(function); } #endregion Public Methods }

Ahora, digamos que tienes

void foo1 ()

void foo2 (int i1)

int foo3 ()

int foo4 (int i1)

... Entonces puedes declarar tu [método asíncrono] como @Romiox

async Task foo1Async(){ return await Ext.ToTask(()=>foo1()); } async Task foo2Async(int i1){ return await Ext.ToTask(()=>foo2(i1)); } async Task<int> foo3Async(){ return await Ext.ToTask(()=>foo3()); } async Task<int> foo4Async(int i1){ return await Ext.ToTask(()=>foo4(i1)); }

O

async Task foo1Async(){ return await Ext.ToTaskAsync(()=>foo1()); } async Task foo2Async(int i1){ return await Ext.ToTaskAsync(()=>foo2(i1)); } async Task<int> foo3Async(){ return await Ext.ToTaskAsync(()=>foo3()); } async Task<int> foo4Async(int i1){ return await Ext.ToTaskAsync(()=>foo4(i1)); }

...

Ahora usa el modo asincrónico y espera por cualquiera de fooAsync, por ejemplo, foo4Async

async Task<int> TestAsync() { ///Initial Code int m=3; ///Call the task var X =foo4Async(m); ///Between ///Do something while waiting comes here ///.. var Result =await X; ///Final ///Some Code here return Result; }