Что такое async и await
async и await — это ключевые слова в C#, которые упрощают написание асинхронного кода, делая его похожим на синхронный. Они позволяют выполнять длительные операции (например, ввод-вывод, сетевые запросы) без блокировки основного потока, что критично для отзывчивости GUI-приложений и производительности серверных приложений.
Как это работает
Модификатор async применяется к методу, указывая, что он содержит асинхронные операции. Такой метод должен возвращать Task, Task<T> или void (последнее — только для обработчиков событий). Возвращаемый Task представляетongoing операцию, которую можно ожидать.
Ключевое слово await приостанавливает выполнение метода до завершения ожидаемой задачи, но не блокирует поток. Вместо этого управление возвращается вызывающему коду, а когда задача завершается, выполнение метода продолжается с того места, где был await. Это позволяет потоку обрабатывать другие задачи, повышая общую эффективность.
Пример
public class Example
{
// Асинхронный метод, возвращающий Task<int>
public async Task<int> GetCalculationAsync()
{
Console.WriteLine("Начало вычислений...");
// Имитация длительной операции без блокировки потока
var result = await Task.Run(() =>
{
Thread.Sleep(5000); // Долгая операция
return 42;
});
Console.WriteLine("Вычисления завершены.");
return result;
}
public async Task ExecuteAsync()
{
int result = await GetCalculationAsync();
Console.WriteLine($"Результат: {result}");
}}
// Точка входа
static async Task Main(string[] args)
{
Example example = new Example();
await example.ExecuteAsync();
}
В этом примере `GetCalculationAsync` запускает длительную операцию в фоновом потоке через `Task.Run`, а `await` приостанавливает выполнение, не блокируя основной поток. После завершения операции метод продолжает работу и возвращает результат.
## Подводные камни
- **Не используйте `async void`** кроме обработчиков событий: исключения в таких методах невозможно перехватить обычным способом, что может привести к падению приложения.
- **Избегайте блокирующих вызовов** (например, `.Result` или `.Wait()`) внутри асинхронных методов — это может вызвать взаимоблокировки (deadlock), особенно в UI-приложениях.
- **Не забывайте про `ConfigureAwait(false)`** в библиотечном коде, чтобы избежать захвата контекста синхронизации и повысить производительность.
- **Асинхронные методы должны быть действительно асинхронными**: если внутри нет `await`, компилятор выдаст предупреждение, а метод будет выполняться синхронно.
## Когда использовать
- **GUI-приложения**: для сохранения отзывчивости интерфейса при длительных операциях (загрузка данных, файловые операции).
- **Веб-приложения**: для эффективной обработки запросов, особенно при обращении к базам данных или внешним сервисам, чтобы не блокировать потоки пула.
- **Любые операции ввода-вывода**: сетевые запросы, чтение/запись файлов, работа с базами данных.
## Коротко
- `async` — модификатор метода, позволяющий использовать `await`; метод возвращает `Task` или `Task<T>`.
- `await` приостанавливает выполнение, не блокируя поток, и возобновляет его после завершения задачи.
- Используйте `async`/`await` для операций ввода-вывода, чтобы не блокировать поток.
- Избегайте `async void` и блокирующих вызовов внутри асинхронных методов.