TGViewer
.NET Разработчик .NET Разработчик @netdeveloperdiary · 6.75K subscribers
Post #249 652
День двести двенадцатый. #ЗаметкиНаПолях
Многопоточность.
9. Async/await. Начало
В C#5 введено понятие асинхронной функции. Это метод (анонимная функция) объявленный с модификатором async, который может использовать выражения await для ожидания операций. Если операция, которую ожидает выражение, ещё не завершена, асинхронная функция немедленно возвращает управление, а затем продолжается с того места, на котором остановилась, когда значение становится доступным (в соответствующем потоке). Естественный ход программы, при котором следующий оператор не выполняется, пока текущий оператор не завершится, сохраняется, но без блокировки потока. В примере ниже приложение Windows Forms извлекает текст из заданного URL и отображает длину HTML кода в элементе Label:
public class AsyncIntro : Form
{
private static readonly HttpClient client = new HttpClient();
private readonly Label label;
private readonly Button button;

public AsyncIntro()
{
…
button.Click += DisplayWebSiteLength;
…
}
async void DisplayWebSiteLength(object sender, EventArgs e)
{
label.Text = "Fetching...";
string text = await client.GetStringAsync("http://csharpindepth.com");
label.Text = text.Length.ToString();
}
…
}

Краткую строку:
string text = await client.GetStringAsync("http://csharpindepth.com");
можно написать подробнее:
Task<string> task = client.GetStringAsync("http://csharpindepth.com");
string text = await task;

Заметьте, что тип задачи - Task<string>, но тип выражения await - просто string. В этом смысле оператор await выполняет операцию развёртывания (когда ожидаемое значение типа Task<TResult>).

Если поместить точку останова на первую строку и выполнить код до неё в отладчике, стек вызовов покажет, что вы находитесь в событии Button.OnClick. Когда вы достигаете await, код проверяет, доступен ли результат, и, если это не так (в данном случае почти всегда), он планирует выполнение продолжения (continuation) после завершения операции. Продолжение – это фактически функция обратного вызова, которая выполняется, когда асинхронная операция завершена (аналогично методу ContinueWith класса Task). Продолжение поддерживает состояние метода (захватывает все доступные переменные), а также выполняется в том же потоке (в данном случае в потоке пользовательского интерфейса).
Если поместить точку останова после выражения await и снова запустить код, то (предполагая, что потребовалось использовать продолжение) в стеке вызовов больше не будет метода Button.OnClick. Этот метод давно завершился. Поначалу такое изменение стека вызовов может шокировать, но это необходимо для работы асинхронного кода. Работа асинхронных методов достигается компилятором путём создания сложного конечного автомата.

Продолжение следует…

Источник: Jon Skeet “C# In Depth”. 4th ed – Manning Publications Co, 2019. Глава 5.
More from @netdeveloperdiary
  1. Sep 30, 2026Post #3356
  2. Sep 29, 2026Фото 3 (с) Анатолий Кулаков
  3. Sep 29, 2026День 2799. Конференция DotNext 2026. Часть 1 25 и 26 сентября в Москве прошла очередная ко…
  4. Sep 28, 2026День 2798. #Оффтоп Утиная Типизация в C# с Помощью Перехватчиков. Часть 2 Некоторое время…
  5. Sep 27, 2026День 2797. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Окончание Начало Продол…
  6. Sep 26, 2026День 2796. #ЗаметкиНаПолях #AI Рабочий процесс с Copilot для .NET. Продолжение Начало Три…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →