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