Основы async/await
1public async Task<string> FetchDataAsync()2{3 using var client = new HttpClient();4 var response = await client.GetStringAsync("https://api.example.com/data");5 return response;6}
▸Когда использовать async/await
Task vs Task<T>
1// Task — без возвращаемого значения2public async Task DoWorkAsync()3{4 await Task.Delay(1000);5}67// Task<T> — с возвращаемым значением8public async Task<int> CalculateAsync()9{10 await Task.Delay(1000);11 return 42;12}
Параллельное выполнение
1public async Task ProcessItemsAsync()2{3 var tasks = new List<Task>();45 foreach (var item in items)6 {7 tasks.Add(ProcessItemAsync(item));8 }910 await Task.WhenAll(tasks);11}1213// Или с результатами14public async Task<List<Result>> FetchAllAsync()15{16 var tasks = urls.Select(url => FetchOneAsync(url));17 var results = await Task.WhenAll(tasks);18 return results.ToList();19}
CancellationToken
1public async Task GetDataAsync(CancellationToken ct)2{3 using var client = new HttpClient();45 // Передаём токен6 var response = await client.GetAsync("https://api.example.com", ct);78 // Проверяем отмену9 ct.ThrowIfCancellationRequested();1011 // Используем в цикле12 while (!ct.IsCancellationRequested)13 {14 await ProcessAsync(ct);15 await Task.Delay(1000, ct);16 }17}1819// Использование20var cts = new CancellationTokenSource();21await.GetDataAsync(cts.Token);2223// Таймаут24cts.CancelAfter(TimeSpan.FromSeconds(5));
ConfigureAwait
1// По умолчанию: true (возвращаемся в synchronization context)2await client.GetStringAsync(url);34// false: не возвращаемся в synchronization context5await client.GetStringAsync(url).ConfigureAwait(false);6// Полезно в библиотеках для избежанияdeadlock
Async streams
1public async IAsyncEnumerable<int> GenerateNumbersAsync()2{3 for (int i = 0; i < 10; i++)4 {5 await Task.Delay(100);6 yield return i;7 }8}910// Использование11await foreach (var number in GenerateNumbersAsync())12{13 Console.WriteLine(number);14}
Типичные ошибки
▸async void
1// ❌ Плохо: async void2public async void Button_Click()3{4 await DoWorkAsync(); // Исключения не ловятся!5}67// ✅ Хорошо: async Task8private async Task HandleClickAsync()9{10 await DoWorkAsync();11}
▸Deadlock
1// ❌ Deadlock2var result = GetDataAsync().Result; // Блокирует поток34// ✅ Решение5var result = await GetDataAsync();
▸ConfigureAwait в UI
1// ✅ В UI-приложении:ConfigureAwait(true) (по умолчанию)2await UpdateUIAsync();3await SaveDataAsync().ConfigureAwait(false); // Не обновляем UI4await UpdateUIAsync();
Task.CompletedTask
1public Task DoNothingAsync()2{3 return Task.CompletedTask; // Избегаем allocations4}
Заключение
async/await — это основа асинхронного программирования в C#. Правильное использование CancellationToken, избегание deadlock и понимание ConfigureAwait критичны для написания надёжного асинхронного кода.