Setelah await pada task yang belum selesai, runtime harus memutuskan thread mana yang menjalankan sisa method. Jawabannya ada pada SynchronizationContext: objek yang merepresentasikan konteks eksekusi tempat kode seharusnya kembali. Kerangka UI seperti Windows Forms dan WPF memasang konteks pada thread antarmuka, sehingga kelanjutan setelah await kembali ke thread UI dan boleh menyentuh kontrol. Program console tidak memasang konteks apa pun, dan properti SynchronizationContext.Current membaca null.
Peran Konteks dan ConfigureAwait #
- Dengan konteks UI terpasang,
awaitmengambil alih penjadwalan: kelanjutan dikirim kembali ke thread UI melalui konteks itu. ConfigureAwait(false)menyatakan kelanjutan tidak perlu kembali ke konteks penangkap; runtime bebas menjalankannya di thread pool.- Pada console tanpa konteks,
ConfigureAwait(false)tidak mengubah perilaku yang terlihat, karena memang tidak ada konteks yang dikembaliki.
Pustaka yang dipakai di mana saja sebaiknya memakai ConfigureAwait(false) agar tidak tergantung konteks pemanggilnya.
Contoh: Memeriksa Konteks di Console #
Kode berikut membaca SynchronizationContext.Current lalu menjalankan kerja latar dengan ConfigureAwait(false):
static async Task KerjaLatarAsync()
{
await Task.Delay(40).ConfigureAwait(false);
Console.WriteLine("Kerja latar selesai dengan ConfigureAwait(false)");
}
// Pemanggil:
object konteks = SynchronizationContext.Current;
string namaKonteks = konteks is null ? "null" : konteks.GetType().Name;
Console.WriteLine($"SynchronizationContext di console: {namaKonteks}");
await KerjaLatarAsync();
Console.WriteLine("Kelanjutan setelah await kembali ke thread pool");Output yang Dihasilkan:
SynchronizationContext di console: null
Kerja latar selesai dengan ConfigureAwait(false)
Kelanjutan setelah await kembali ke thread poolMari kita bedah baris-barisnya:
SynchronizationContext.Current: properti statis membaca konteks thread saat ini; di console program nilainyanull, tercetak lewat pemeriksaanis null.await Task.Delay(40).ConfigureAwait(false): penundaan ditunggu tanpa penangkapan konteks; kelanjutan bebas berjalan di thread pool.Console.WriteLine("Kerja latar selesai ..."): baris ini adalah kelanjutan; di console tidak ada perbedaan yang terlihat, tetapi pada aplikasi UI baris yang sama tidak boleh menyentuh kontrol.Console.WriteLine("Kelanjutan setelah await ..."): pemanggil menunggu task selesai; tanpa konteks, kelanjutan pemanggil juga berjalan di thread pool.
Kesadaran akan konteks ini menyiapkan kita memahami kebuntuan klasik pada bab berikutnya.