async/await kullanırken .Result veya .Wait() çağırmak neden deadlock'a yol açabilir? ConfigureAwait(false) ne işe yarar?
Cevap
await varsayılan olarak devamı (continuation) yakaladığı SynchronizationContext üzerinde çalıştırmaya çalışır. O bağlam tek thread'liyse (WinForms/WPF UI thread'i, klasik ASP.NET) ve siz o thread'i .Result ile bloklarsanız, devam asla çalışamaz: deadlock.
// Klasik ASP.NET (System.Web) veya UI uygulaması
public string Get()
{
return GetDataAsync().Result; // UI/istek thread'i burada bloklanır
}
async Task<string> GetDataAsync()
{
var s = await http.GetStringAsync(url); // devam aynı thread'e dönmek ister
return s; // ama o thread .Result'ta bekliyor
}ConfigureAwait(false)
await task.ConfigureAwait(false) devamın yakalanan bağlama dönmek zorunda olmadığını söyler; thread pool'da çalışır. Kütüphane kodunda önerilir, çünkü kütüphane hangi bağlamda çağrılacağını bilemez.
ASP.NET Core'da durum
ASP.NET Core'da SynchronizationContext yoktur, bu yüzden bu klasik deadlock oluşmaz. Ancak .Result / .Wait() yine de kötüdür:
- Thread pool starvation: her bloklama bir thread pool thread'ini boşa tutar. Yük altında yeni thread'ler yavaş eklendiği için istekler birikir, gecikme saniyelere çıkar.
- Exception'lar
AggregateExceptioniçine sarılır.
Doğru kurallar
- "Async all the way": çağrı zincirinin tepesine kadar
async/awaitkullanın. async voidyalnızca event handler'larda; diğer yerlerdeTaskdöndürün (async void exception'ları yakalanamaz ve process'i çökertebilir).CancellationToken'ı controller'dan DB çağrısına kadar geçirin.- Zorunluysa senkron bağlamda
GetAwaiter().GetResult()kullanın (exception sarılmaz), ama bloklama sorunu aynıdır. - Sık tamamlanan sıcak yollar için
ValueTaskallocation'ı azaltır; birValueTaskyalnızca bir kez await edilmelidir.
İlgili C# & .NET soruları
- .NET'te Garbage Collector nasıl çalışır? Generation'lar, Large Object Heap ve IDisposable ilişkisini açıklayın.
- EF Core'da change tracking nasıl çalışır? AsNoTracking ne zaman kullanılır ve N+1 problemi nasıl önlenir?
- IEnumerable<T> ile IQueryable<T> arasındaki fark nedir? EF Core'da yanlış kullanım ne gibi sorunlara yol açar?
- LINQ'te deferred execution nedir? Aşağıdaki kodun çıktısı ne olur?
- ASP.NET Core DI'da Transient, Scoped ve Singleton lifetime'ları arasındaki fark nedir? Captive dependency nedir?
- ASP.NET Core'da middleware pipeline nasıl çalışır? Use, Run ve Map farkı nedir, sıralama neden önemlidir?
Bu konuda başka bir soru biliyor musun?
Mülakatta karşılaştığın soruları ekle, onaylandıktan sonra yayına alınsın.