Innanzitutto, chiariamo alcuni termini: "asincrono" ( async) significa che potrebbe restituire il controllo al thread chiamante prima che inizi. In un asyncmetodo, quei punti di "rendimento" sonoawait espressioni.
Questo è molto diverso dal termine "asincrono", poiché (mis) usato da anni dalla documentazione MSDN per significare "esegue su un thread in background".
Per confondere ulteriormente il problema, asyncè molto diverso da "aspettabile"; ci sono alcuni asyncmetodi i cui tipi di restituzione non sono attendibili e molti metodi che restituiscono tipi attendibili che non lo sono async.
Basta con quello che non sono ; ecco cosa sono :
- La
asyncparola chiave consente un metodo asincrono (ovvero consente awaitespressioni). asynci metodi possono restituire Task, Task<T>oppure (se necessario) void.
- Qualsiasi tipo che segue un certo modello può essere attendibile. I tipi più comuni attesi sono
Taske Task<T>.
Quindi, se riformuliamo la tua domanda su "come posso eseguire un'operazione su un thread in background in modo che sia attendibile", la risposta è usare Task.Run:
private Task<int> DoWorkAsync() // No async because the method does not need await
{
return Task.Run(() =>
{
return 1 + 2;
});
}
(Ma questo modello è un approccio scadente; vedi sotto).
Ma se la tua domanda è "come posso creare un asyncmetodo che può restituire al suo chiamante invece di bloccare", la risposta è dichiarare il metodo asynce usare awaitper i suoi punti "cedenti":
private async Task<int> GetWebPageHtmlSizeAsync()
{
var client = new HttpClient();
var html = await client.GetAsync("http://www.example.com/");
return html.Length;
}
Quindi, lo schema di base delle cose è che il asynccodice dipenda da "attendibili" nelle sue awaitespressioni. Questi "attendibili" possono essere altri asyncmetodi o solo metodi regolari che restituiscono gli aspetti attendibili. Metodi regolari ritorno Task/ Task<T> possono utilizzare Task.Runper eseguire codice su un thread in background, o (più comunemente) che possono utilizzare TaskCompletionSource<T>o uno dei suoi tasti di scelta rapida ( TaskFactory.FromAsync, Task.FromResult, ecc). Io non consiglio avvolgendo un intero metodo Task.Run; i metodi sincroni dovrebbero avere firme sincrone e dovrebbe essere lasciato al consumatore se debba essere racchiuso in 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());
...
}
Ho async/ awaitintro sul mio blog; alla fine ci sono alcune buone risorse di follow-up. Anche i documenti MSDN per asyncsono insolitamente buoni.