Спочатку давайте розберемо деяку термінологію: "асинхронний" ( 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
також незвичайно хороші.