Pembaruan: ASP.NET Core tidak memilikiSynchronizationContext
. Jika Anda menggunakan ASP.NET Core, tidak masalah apakah Anda menggunakan ConfigureAwait(false)
atau tidak.
Untuk ASP.NET "Penuh" atau "Klasik" atau apa pun, sisa jawaban ini masih berlaku.
Posting asli (untuk ASP.NET non-Core):
Video ini oleh tim ASP.NET memiliki informasi terbaik tentang penggunaan async
di ASP.NET.
Saya telah membaca bahwa itu lebih berkinerja karena tidak harus mengubah konteks utas kembali ke konteks utas asli.
Ini berlaku untuk aplikasi UI, di mana hanya ada satu utas UI yang harus "disinkronkan" kembali.
Di ASP.NET, situasinya sedikit lebih kompleks. Ketika suatu async
metode melanjutkan eksekusi, itu mengambil sebuah utas dari kumpulan utas ASP.NET. Jika Anda menonaktifkan pengambilan konteks menggunakan ConfigureAwait(false)
, maka utas hanya melanjutkan menjalankan metode secara langsung. Jika Anda tidak menonaktifkan tangkapan konteks, maka utas akan memasukkan kembali konteks permintaan dan kemudian melanjutkan untuk mengeksekusi metode.
Jadi ConfigureAwait(false)
tidak menghemat lompatan thread di ASP.NET; itu tidak menyelamatkan Anda memasukkan kembali konteks permintaan, tetapi ini biasanya sangat cepat. ConfigureAwait(false)
bisa berguna jika Anda mencoba melakukan sejumlah kecil pemrosesan paralel permintaan, tetapi sebenarnya TPL lebih cocok untuk sebagian besar skenario tersebut.
Namun, dengan ASP.NET Web Api, jika permintaan Anda masuk dalam satu utas, dan Anda menunggu beberapa fungsi dan memanggil ConfigureAwait (false) yang berpotensi menempatkan Anda pada utas yang berbeda ketika Anda mengembalikan hasil akhir dari fungsi ApiController Anda .
Sebenarnya, hanya melakukan await
dapat melakukan itu. Setelah async
metode Anda await
mengenai, metode diblokir tetapi utas kembali ke kumpulan utas. Ketika metode siap untuk melanjutkan, semua utas diambil dari kumpulan utas dan digunakan untuk melanjutkan metode.
Satu-satunya perbedaan ConfigureAwait
di ASP.NET adalah apakah utas itu memasuki konteks permintaan saat melanjutkan metode.
Saya memiliki lebih banyak informasi latar belakang di artikel MSDNSynchronizationContext
saya dan async
posting blog intro saya .
HttpContext.Current
mengalir oleh ASP.NETSynchronizationContext
, yang mengalir secara default saat Andaawait
, tetapi tidak mengalir olehContinueWith
. OTOH, konteks eksekusi (termasuk pembatasan keamanan) adalah konteks disebutkan dalam CLR melalui C #, dan itu adalah mengalir dengan baikContinueWith
danawait
(bahkan jika Anda menggunakanConfigureAwait(false)
).ConfigureAwait
sebenarnya hanya masuk akal ketika Anda menunggu tugas , sedangkanawait
bertindak pada "ditunggu." Opsi lain yang dipertimbangkan adalah: Haruskah perilaku default membuang konteks jika di perpustakaan? Atau ada pengaturan kompiler untuk perilaku konteks default? Keduanya ditolak karena lebih sulit untuk hanya membaca kode dan mengatakan apa yang dilakukannya.ConfigureAwait(false)
untuk menghindariResult
/Wait
berbasis kebuntuan karena pada ASP.NET Anda tidak harus menggunakanResult
/Wait
di tempat pertama.Jawaban singkat untuk pertanyaan Anda: Tidak. Anda tidak boleh menelepon
ConfigureAwait(false)
di tingkat aplikasi seperti itu.TL; Versi DR dari jawaban yang panjang: Jika Anda menulis perpustakaan di mana Anda tidak mengenal konsumen Anda dan tidak memerlukan konteks sinkronisasi (yang seharusnya tidak Anda temukan di perpustakaan, saya harus selalu menggunakannya
ConfigureAwait(false)
. Jika tidak, konsumen perpustakaan Anda mungkin menghadapi kebuntuan dengan mengonsumsi metode asinkron Anda dengan cara memblokir. Ini tergantung situasi.Berikut adalah penjelasan yang sedikit lebih rinci tentang pentingnya
ConfigureAwait
metode (kutipan dari posting blog saya):Juga, berikut adalah dua artikel bagus untuk Anda yang tepat untuk pertanyaan Anda:
Akhirnya, ada video pendek yang bagus dari Lucian Wischik tepatnya tentang topik ini: Metode perpustakaan Async harus mempertimbangkan untuk menggunakan Task.ConfigureAwait (false) .
Semoga ini membantu.
sumber
Task
berjalan tumpukan untuk mendapatkanSynchronizationContext
, yang salah. TheSynchronizationContext
adalah meraih sebelum panggilan keTask
dan kemudian sisa kode dilanjutkan padaSynchronizationContext
jikaSynchronizationContext.Current
tidak null.SynchronizationContext.Current
itu jelas / atau bahwa perpustakaan dipanggil di dalamTask.Run()
daripada harus menulis di.ConfigureAwait(false)
seluruh perpustakaan kelas?.ConfigureAwait(false)
. Mungkin akan lebih mudah bagi penulis perpustakaan jika itu adalah perilaku default, tetapi saya akan berasumsi bahwa membuat sedikit lebih sulit untuk menulis perpustakaan dengan benar lebih baik daripada membuatnya sedikit lebih sulit untuk menulis aplikasi dengan benar.Kelemahan terbesar yang saya temukan dengan menggunakan ConfigureAwait (false) adalah budaya thread dikembalikan ke default sistem. Jika Anda mengkonfigurasi budaya misalnya ...
dan Anda hosting di server yang budayanya diatur ke en-AS, maka Anda akan menemukan sebelum ConfigureAwait (false) disebut CultureInfo.CurrentCulture akan mengembalikan en-AU dan setelah Anda mendapatkan en-AS. yaitu
Jika aplikasi Anda melakukan sesuatu yang membutuhkan pemformatan khusus data kultur, maka Anda harus memperhatikan hal ini saat menggunakan ConfigureAwait (false).
sumber
ConfigureAwait(false)
digunakan.Saya memiliki beberapa pemikiran umum tentang implementasi
Task
:using
.ConfigureAwait
diperkenalkan pada 4.5.Task
diperkenalkan pada 4.0.Task.ContinueWith
mereka tidak b / c disadari bahwa konteks switch mahal dan dimatikan secara default.Saya sudah mendapat beberapa posting tentang masalah ini tetapi pendapat saya - selain jawaban bagus Tugberk - adalah bahwa Anda harus mengubah semua API tidak sinkron dan idealnya mengalir konteksnya. Karena Anda melakukan async, Anda cukup menggunakan kelanjutan alih-alih menunggu sehingga tidak ada jalan buntu yang disebabkan karena tidak ada menunggu dilakukan di perpustakaan dan Anda tetap mengalir agar konteksnya dipertahankan (seperti HttpContext).
Masalahnya adalah ketika perpustakaan memperlihatkan API sinkron tetapi menggunakan API asinkron lain - maka Anda perlu menggunakan
Wait()
/Result
dalam kode Anda.sumber
Task.Dispose
jika Anda mau; Anda hanya tidak perlu untuk sebagian besar waktu. 2)Task
diperkenalkan di .NET 4.0 sebagai bagian dari TPL, yang tidak perluConfigureAwait
; ketikaasync
ditambahkan, mereka menggunakan kembaliTask
jenis yang sudah ada alih-alih menciptakan yang baruFuture
.Task
s; "konteks" yang dikendalikan olehContinueWith
adalah aSynchronizationContext
atauTaskScheduler
. Konteks yang berbeda ini dijelaskan secara rinci di blog Stephen Toub .Thread
s, tetapi tidak lagi denganContinueWith()
), ini membuat jawaban Anda membingungkan untuk dibaca.