Async await в C#: первый пример без магии

async и await нужны не для того, чтобы любая программа стала быстрее. Они нужны, чтобы удобно писать код, который ждет: HTTP-запрос, файл, базу данных, таймер, внешний сервис. В этом уроке сделаем маленький пример с загрузкой профиля пользователя и разберем Task, async, await без мистики

Главная мысль: await не «создает поток». Он позволяет методу приостановиться, пока операция не завершится, и продолжить выполнение позже

Что получится в конце

Программа выведет:

Загружаю профиль...
Профиль: Алия
Готово

Код будет похож на обычный последовательный код, хотя внутри есть ожидание

Создаем проект

dotnet new console -n CSharpAsync
cd CSharpAsync

В Program.cs:

Console.WriteLine("Загружаю профиль...");

var profile = await LoadProfileAsync(1);

Console.WriteLine($"Профиль: {profile.Name}");
Console.WriteLine("Готово");

static async Task<UserProfile> LoadProfileAsync(int userId)
{
    await Task.Delay(1000);
    return new UserProfile(userId, "Алия");
}

public record UserProfile(int Id, string Name);

Запустите:

dotnet run

Современный C# позволяет использовать await в top-level statements, поэтому отдельный static async Task Main() в первом примере не нужен

Что такое Task

Task<UserProfile> означает: операция когда-нибудь завершится и даст UserProfile

static async Task<UserProfile> LoadProfileAsync(int userId)

Метод не возвращает профиль сразу. Он возвращает задачу, которую можно ожидать:

var profile = await LoadProfileAsync(1);

После await в переменной profile будет уже результат, а не сама задача

Если метод ничего не возвращает, но тоже асинхронный, обычно пишут:

static async Task SaveAsync()

Не void, а Task. async void оставляют почти только для обработчиков событий в UI

Что делает await

Строка:

await Task.Delay(1000);

имитирует ожидание в одну секунду. В реальном коде вместо этого может быть чтение файла, запрос к API или обращение к базе данных

await говорит: дождись завершения операции, а потом продолжай метод. Поэтому код читается сверху вниз:

  1. Напечатали «Загружаю профиль…».
  2. Дождались профиля.
  3. Напечатали имя.
  4. Напечатали «Готово».

Обработка ошибок в async-коде

Ошибки в асинхронных методах обрабатываются обычным try/catch:

try
{
    var profile = await LoadProfileAsync(0);
    Console.WriteLine(profile.Name);
}
catch (InvalidOperationException ex)
{
    Console.WriteLine($"Ошибка: {ex.Message}");
}

Изменим метод:

static async Task<UserProfile> LoadProfileAsync(int userId)
{
    await Task.Delay(1000);

    if (userId <= 0)
    {
        throw new InvalidOperationException("Некорректный ID пользователя");
    }

    return new UserProfile(userId, "Алия");
}

Когда задача завершается с ошибкой, await достает эту ошибку и бросает ее в месте ожидания. Поэтому try/catch вокруг await работает естественно

Где async не помогает

Если задача чисто вычислительная и быстро выполняется на CPU, async/await сам по себе не ускорит ее

Плохой пример:

static async Task<int> SumAsync(int a, int b)
{
    return a + b;
}

Здесь нечего ждать. Обычный метод лучше:

static int Sum(int a, int b) => a + b;

Асинхронность полезна там, где есть ожидание внешней операции

Частые ошибки

Забыли await. Тогда в переменной окажется Task, а не результат. Компилятор часто подсказывает это сразу

async void. Не используйте для обычных методов. Ошибки из async void сложнее контролировать

Блокировка через .Result или .Wait(). В учебном консольном коде иногда работает, но в приложениях может приводить к блокировкам. Лучше распространять async вверх и использовать await

Название без Async. Это не ошибка компиляции, но стандарт .NET рекомендует добавлять Async к асинхронным методам

Что может быть еще интересно по этой теме

Async делает код параллельным? Не обязательно. Он делает ожидание неблокирующим и удобным для чтения. Параллельность — отдельная тема

Task и Thread это одно и то же? Нет. Task представляет операцию, а не обязательно отдельный поток

Нужно ли async в ASP.NET Core? Да, при работе с базой, файлами и внешними API. Это помогает серверу не держать поток без дела во время ожидания

Почему почти все библиотеки имеют методы с Async? Потому что I/O-операции лучше ждать асинхронно, особенно в серверных приложениях

Что открыть дальше

Оцените статью
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x