Primero, aclaremos algo de terminología: "asíncrono" ( async) significa que puede ceder el control al hilo de llamada antes de que comience. En un asyncmétodo, esos puntos de "rendimiento" son awaitexpresiones.
Esto es muy diferente al término "asíncrono", ya que (mal) usado por la documentación de MSDN durante años significa "se ejecuta en un hilo de fondo".
Para confundir aún más el tema, asynces muy diferente de "espera"; Hay algunos asyncmétodos cuyos tipos de retorno no son esperados, y muchos métodos que devuelven tipos que no lo son async.
Suficiente sobre lo que no son ; esto es lo que son :
- La
asyncpalabra clave permite un método asincrónico (es decir, permite awaitexpresiones). asynclos métodos pueden regresar Task, Task<T>o (si debe hacerlo) void.
- Cualquier tipo que siga un cierto patrón puede estar a la espera. Los tipos de espera más comunes son
Tasky Task<T>.
Entonces, si reformulamos su pregunta a "¿cómo puedo ejecutar una operación en un subproceso en segundo plano de una manera que sea esperable", la respuesta es usar Task.Run:
private Task<int> DoWorkAsync() // No async because the method does not need await
{
return Task.Run(() =>
{
return 1 + 2;
});
}
(Pero este patrón es un enfoque pobre; ver más abajo).
Pero si su pregunta es "¿cómo creo un asyncmétodo que pueda ceder el paso a su interlocutor en lugar de bloquearlo", la respuesta es declarar el método asyncy usarlo awaitpara sus puntos de "ceder":
private async Task<int> GetWebPageHtmlSizeAsync()
{
var client = new HttpClient();
var html = await client.GetAsync("http://www.example.com/");
return html.Length;
}
Por lo tanto, el patrón básico de las cosas es que el asynccódigo dependa de "esperables" en sus awaitexpresiones. Estos "esperables" pueden ser otros asyncmétodos o simplemente métodos regulares que devuelven objetos esperables. Métodos habituales que regresan Task/ Task<T> pueden utilizar Task.Runpara ejecutar código en un subproceso en segundo plano, o (más comúnmente) que pueden utilizar TaskCompletionSource<T>o uno de sus accesos directos ( TaskFactory.FromAsync, Task.FromResult, etc.). Yo no recomiendo el embalaje de un método completo en Task.Run; los métodos síncronos deben tener firmas síncronas, y debe dejarse en manos del consumidor si debe estar envuelto en un Task.Run:
private int DoWork()
{
return 1 + 2;
}
private void MoreSynchronousProcessing()
{
// Execute it directly (synchronously), since we are also a synchronous method.
var result = DoWork();
...
}
private async Task DoVariousThingsFromTheUIThreadAsync()
{
// I have a bunch of async work to do, and I am executed on the UI thread.
var result = await Task.Run(() => DoWork());
...
}
Tengo una async/ awaitintroducción en mi blog; al final hay algunos buenos recursos de seguimiento. Los documentos de MSDN para también asyncson inusualmente buenos.