Что такое асинхронность
Асинхронность — это подход к выполнению операций, при котором вызов метода не блокирует текущий поток, а позволяет ему продолжить выполнение других задач, пока операция выполняется в фоне. В C# асинхронность реализуется с помощью ключевых слов async и await, а также типов Task и Task<T>. Это позволяет писать код, который выглядит синхронно, но при этом не блокирует поток, что критично для отзывчивости UI и масштабируемости серверных приложений.
Как это работает
Асинхронный метод помечается ключевым словом async. Внутри такого метода обязательно должен быть хотя бы один оператор await. Когда выполнение доходит до await, метод приостанавливается и возвращает управление вызывающему коду, а поток освобождается для выполнения других задач. После завершения асинхронной операции выполнение метода продолжается с того места, где был await.
Важно понимать, что await не блокирует поток, а лишь приостанавливает выполнение текущего метода. Это достигается за счет того, что компилятор преобразует асинхронный метод в конечный автомат, который отслеживает состояние выполнения.
Пример
public async Task<string> GetDataAsync()
{
using HttpClient client = new();
// await приостанавливает выполнение, не блокируя поток
string result = await client.GetStringAsync("https://api.example.com/data");
return result;
}В этом примере GetDataAsync возвращает Task<string>. При вызове await client.GetStringAsync(...) поток освобождается, а когда данные будут получены, выполнение метода продолжится, и результат будет возвращен.
Преимущества и подводные камни
Преимущества асинхронности:
- Эффективное использование потоков: потоки не простаивают в ожидании завершения операций ввода-вывода.
- Отзывчивость UI: интерфейс не зависает при выполнении длительных операций.
- Масштабируемость серверных приложений: меньше потоков требуется для обработки большого количества запросов.
Подводные камни:
- Deadlock: возникает, когда асинхронный метод вызывается синхронно (например, через
.Resultили.Wait()) в контексте с синхронизацией (например, UI-поток). Чтобы избежать, используйтеConfigureAwait(false)в библиотечном коде или не блокируйте поток при вызове асинхронных методов. - Исключения: в асинхронных методах исключения сохраняются в
Taskи выбрасываются приawait. Обрабатывайте их с помощьюtry-catchвокругawait. - Неправильное использование
asyncбезawaitприводит к предупреждению компилятора и не дает преимуществ.
Когда использовать
Асинхронность следует использовать для операций ввода-вывода (сеть, файлы, базы данных) и длительных операций, которые не требуют интенсивного использования CPU. Для CPU-интенсивных задач лучше подходит Task.Run или параллельное программирование.
Коротко
- Асинхронность позволяет не блокировать поток при выполнении операций.
- В C# используется
async/awaitиTask/Task<T>. awaitприостанавливает метод, но не блокирует поток.- Избегайте deadlock'ов и правильно обрабатывайте исключения.