Ответ 1
Во-первых, позвольте прояснить некоторую терминологию: "асинхронный" (async
) означает, что он может вернуть управление вызывающему потоку до его запуска. В методе async
те точки "yield" являются выражениями 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
зависел от "awaitables" в выражениях await
. Этими "ожидающими" могут быть другие методы async
или просто регулярные методы, возвращающие awaitables. Регулярные методы, возвращающие 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
intro в моем блоге; в конце есть некоторые хорошие последующие ресурсы. Документы MSDN для async
также необычайно хороши.