Встречается на 33% собеседований по C#

Как используется ключевое слово await

Ключевое слово await в C# используется для ожидания завершения асинхронной операции без блокирования текущего потока. Оно позволяет приложению оставаться отзывчивым во время выполнения длительных операций, таких как сетевые запросы, работа с файлами или базами данных. await применяется только внутри методов, помеченных модификатором async, и работает с объектами, реализующими паттерн ожидания (обычно Task или Task<T>).

Как это работает

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

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

Пример

csharp
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 и избегайте блокирующих вызовов рядом с ним.
как отвечать на вопрос
пример собеседования
фреймворки на собеседовании
типичные вопросы junior
интервью вопросы и ответы