Najpierw wyjaśnijmy trochę terminologii: „asynchroniczny” ( async
) oznacza, że może odzyskać kontrolę nad wątkiem wywołującym przed jego uruchomieniem. W async
metodzie te punkty „ustępowania” są await
wyrażeniami.
Jest to bardzo różni się od terminu „asynchroniczny”, ponieważ (błędnie) używany w dokumentacji MSDN od lat oznacza „wykonuje się w wątku w tle”.
Dalsze mylenie problemu async
jest zupełnie inne niż „oczekiwanie”; istnieją async
metody, których typy zwracane są nieoczekiwane, i wiele metod zwracających oczekiwane typy, które nie są oczekiwane async
.
Dość o tym, czym nie są ; oto czym one są :
- Słowo
async
kluczowe pozwala na metodę asynchroniczną (tzn. Pozwala na await
wyrażenia). async
metody mogą zwrócić Task
, Task<T>
lub (jeśli musisz) void
.
- Każdy typ zgodny z określonym wzorcem może być oczekiwany. Najczęściej spotykanymi typami są
Task
i Task<T>
.
Jeśli więc przeformułujemy twoje pytanie na „jak mogę uruchomić operację na wątku w tle w sposób, w jaki jest to oczekiwane”, odpowiedzią jest użycie Task.Run
:
private Task<int> DoWorkAsync() // No async because the method does not need await
{
return Task.Run(() =>
{
return 1 + 2;
});
}
(Ale ten wzór jest złym podejściem; patrz poniżej).
Ale jeśli twoje pytanie brzmi: „jak utworzyć async
metodę, która może ustępować swojemu programowi wywołującemu zamiast blokować”, odpowiedzią jest zadeklarowanie metody async
i użycie await
jej punktów „ustępujących”:
private async Task<int> GetWebPageHtmlSizeAsync()
{
var client = new HttpClient();
var html = await client.GetAsync("http://www.example.com/");
return html.Length;
}
Zatem podstawowym wzorem rzeczy jest async
zależność kodu od „oczekiwań” w jego await
wyrażeniach. Te „oczekiwane” mogą być innymi async
metodami lub zwykłymi metodami zwracającymi oczekiwane. Zwykłe metody powracający Task
/ Task<T>
można użyć Task.Run
do wykonania kodu w wątku tła, lub (częściej) mogą używać TaskCompletionSource<T>
lub jeden z jego (skróty TaskFactory.FromAsync
, Task.FromResult
itp). I nie polecam owijania całą metodę in Task.Run
; metody synchroniczne powinny mieć sygnatury synchroniczne i konsument powinien pozostawić pytanie, czy ma być zawinięty w 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());
...
}
Mam async
/ await
intro na moim blogu; na końcu są dobre zasoby uzupełniające. Dokumenty MSDN dla async
są również niezwykle dobre.