Спочатку давайте розберемо деяку термінологію: "асинхронний" ( async) означає, що він може повернути керування поточному виклику до запуску. У asyncметоді ці точки "дохідності" є awaitвиразами.
Це дуже відрізняється від терміна "асинхронний", оскільки (помилка), що використовується документацією MSDN роками, означає "виконується на фоновому потоці".
Для подальшої плутанини питання, asyncце зовсім інше, ніж "очікуване"; Є кілька asyncметодів, типи повернення яких не чекають, і багато методів повернення очікуваних типів, яких немає async.
Досить про те, чого вони не є ; ось те , що вони є :
asyncКлючове слово дозволяє асинхронний метод (тобто, це дозволяє awaitвираження). asyncметоди можуть повернутися Task, Task<T>або (якщо потрібно) void.
- Будь-який тип, який слідує певній схемі, може бути очікуваним. Найпоширенішими типами, що очікуються, є
Taskі Task<T>.
Отже, якщо ми переформулюємо ваше запитання на тему "як я можу виконати операцію над фоновою ниткою так, щоб це було очікувано", відповідь полягає у використанні Task.Run:
private Task<int> DoWorkAsync() // No async because the method does not need await
{
return Task.Run(() =>
{
return 1 + 2;
});
}
(Але ця схема є поганим підходом; див. Нижче).
Але якщо ваше запитання полягає в тому, як "створити asyncметод, який може повернутись до свого абонента, а не блокувати", відповідь полягає в оголошенні методу asyncта використанні awaitйого "поступальних" балів:
private async Task<int> GetWebPageHtmlSizeAsync()
{
var client = new HttpClient();
var html = await client.GetAsync("http://www.example.com/");
return html.Length;
}
Отже, основна закономірність речей полягає в тому, щоб asyncкод залежав від "очікуваного" в його awaitвиразах. Ці "очікувані" можуть бути іншими asyncметодами або просто звичайними методами, що повертають очікувані. Звичайні методи , які повертають Task/ Task<T> можна використовувати Task.Runдля виконання коду в фоновому потоці, або (частіше) вони можуть використовувати TaskCompletionSource<T>або один з його ярликів ( TaskFactory.FromAsync, Task.FromResultі т.д.). Я не рекомендую обгортати весь метод Task.Run; синхронні методи повинні мати синхронні підписи, і споживачеві слід залишати, чи він повинен бути загорнутий у 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());
...
}
У мене є async/ awaitінтро в моєму блозі; наприкінці - кілька хороших подальших ресурсів. Документи MSDN для asyncтакож незвичайно хороші.