Как используется ключевое слово await
Ключевое слово await в C# используется для ожидания завершения асинхронной операции без блокирования текущего потока. Оно позволяет приложению оставаться отзывчивым во время выполнения длительных операций, таких как сетевые запросы, работа с файлами или базами данных. await применяется только внутри методов, помеченных модификатором async, и работает с объектами, реализующими паттерн ожидания (обычно Task или Task<T>).
Как это работает
Когда компилятор встречает await, он преобразует метод в конечный автомат, который позволяет приостанавливать и возобновлять выполнение. При достижении оператора await текущий метод возвращает управление вызывающему коду, а поток освобождается для выполнения других задач. Когда асинхронная операция завершается, выполнение метода возобновляется с того места, где был await, при этом результат операции становится доступен.
Важно понимать, что await не блокирует поток, а лишь приостанавливает выполнение текущего метода. Это позволяет эффективно использовать системные ресурсы, особенно в приложениях с графическим интерфейсом, где блокировка потока привела бы к зависанию интерфейса.
Пример
using System;
using System.Net.Http;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
string content = await FetchWebPageAsync("https://example.com");
Console.WriteLine(content);
}
static async Task<string> FetchWebPageAsync(string url)
{
using (HttpClient client = new HttpClient())
{
HttpResponseMessage response = await client.GetAsync(url);
return await response.Content.ReadAsStringAsync();
}
}
}В этом примере метод FetchWebPageAsync асинхронно загружает веб-страницу. await используется дважды: первый раз для ожидания завершения GetAsync, который отправляет HTTP-запрос, и второй раз для ожидания ReadAsStringAsync, который асинхронно читает ответ в виде строки. Пока эти операции выполняются, поток не блокируется, и приложение может обрабатывать другие события.
Подводные камни
awaitможно использовать только в методах с модификаторомasync. Исключение — методMainв C# 7.1 и новее, где допускаетсяasync Task Main.- Если асинхронная операция завершилась с ошибкой,
awaitвыбросит исключение в месте ожидания. Обрабатывайте исключения черезtry-catchвокругawait. - Не используйте
awaitв циклах, если операции независимы — лучше использоватьTask.WhenAllдля параллельного выполнения. - Избегайте смешивания синхронных блокирующих вызовов (например,
.Resultили.Wait()) сawait, так как это может привести к взаимоблокировкам (deadlock) в контексте синхронизации. - В библиотеках, не связанных с UI, используйте
ConfigureAwait(false), чтобы избежать захвата контекста синхронизации и повысить производительность.
Когда использовать
await следует использовать для любых операций, которые могут занять значительное время: сетевые запросы, чтение/запись файлов, обращение к базам данных, длительные вычисления. Это особенно важно в UI-приложениях (WPF, WinForms, ASP.NET), где блокировка потока приведет к зависанию интерфейса или снижению пропускной способности сервера.
Коротко
awaitприостанавливает выполнение метода, не блокируя поток, и возобновляет его после завершения асинхронной операции.- Используется только в
async-методах с типамиTaskилиTask<T>. - Позволяет приложению оставаться отзывчивым и эффективно использовать ресурсы.
- Обрабатывайте исключения вокруг
awaitи избегайте блокирующих вызовов рядом с ним.