Во-первых, давайте проясним некоторую терминологию: «асинхронный» ( 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тоже необычайно хороши.