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 AggregateException içine sarılır.

Doğru kurallar

  • "Async all the way": çağrı zincirinin tepesine kadar async / await kullanın.
  • async void yalnızca event handler'larda; diğer yerlerde Task dö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 ValueTask allocation'ı azaltır; bir ValueTask yalnızca bir kez await edilmelidir.
  1. .NET'te Garbage Collector nasıl çalışır? Generation'lar, Large Object Heap ve IDisposable ilişkisini açıklayın.ZorC# & .NETBackend
  2. EF Core'da change tracking nasıl çalışır? AsNoTracking ne zaman kullanılır ve N+1 problemi nasıl önlenir?OrtaC# & .NETBackend
  3. IEnumerable<T> ile IQueryable<T> arasındaki fark nedir? EF Core'da yanlış kullanım ne gibi sorunlara yol açar?KolayC# & .NETBackend
  4. LINQ'te deferred execution nedir? Aşağıdaki kodun çıktısı ne olur?OrtaC# & .NETBackend
  5. ASP.NET Core DI'da Transient, Scoped ve Singleton lifetime'ları arasındaki fark nedir? Captive dependency nedir?OrtaC# & .NETBackend
  6. ASP.NET Core'da middleware pipeline nasıl çalışır? Use, Run ve Map farkı nedir, sıralama neden önemlidir?OrtaC# & .NETBackend

Bu konuda başka bir soru biliyor musun?

Mülakatta karşılaştığın soruları ekle, onaylandıktan sonra yayına alınsın.

Soru ekle