Pemrograman asinkron tidak "tumbuh" melalui basis kode. Ini telah dibandingkan dengan virus zombie . Solusi terbaik adalah membiarkannya tumbuh, tetapi terkadang itu tidak mungkin.
Saya telah menulis beberapa jenis di pustaka Nito.AsyncEx saya untuk berurusan dengan basis kode asinkron parsial. Tidak ada solusi yang berfungsi di setiap situasi.
Solusi A
Jika Anda memiliki metode asinkron sederhana yang tidak perlu disinkronkan kembali ke konteksnya, maka Anda dapat menggunakan Task.WaitAndUnwrapException:
var task = MyAsyncMethod();
var result = task.WaitAndUnwrapException();
Anda tidak ingin menggunakan Task.Waitatau Task.Resultkarena mereka memasukkan pengecualian AggregateException.
Solusi ini hanya sesuai jika MyAsyncMethodtidak disinkronkan kembali ke konteksnya. Dengan kata lain, setiap awaitdi MyAsyncMethodharus berakhir dengan ConfigureAwait(false). Ini berarti tidak dapat memperbarui elemen UI apa pun atau mengakses konteks permintaan ASP.NET.
Solusi B
Jika MyAsyncMethodmemang perlu disinkronkan kembali ke konteksnya, maka Anda mungkin dapat menggunakan AsyncContext.RunTaskuntuk memberikan konteks bersarang:
var result = AsyncContext.RunTask(MyAsyncMethod).Result;
* Pembaruan 4/14/2014: Dalam versi perpustakaan yang lebih baru, API adalah sebagai berikut:
var result = AsyncContext.Run(MyAsyncMethod);
(Tidak apa-apa untuk digunakan Task.Resultdalam contoh ini karena RunTaskakan menyebarkan Taskpengecualian).
Alasan Anda mungkin perlu AsyncContext.RunTaskbukannya Task.WaitAndUnwrapExceptionkarena kebuntuan yang agak halus yang terjadi pada WinForms / WPF / SL / ASP.NET:
- Metode sinkron memanggil metode async, memperoleh a
Task.
- Metode sinkron melakukan pemblokiran menunggu di Internet
Task.
- The
asyncMetode menggunakan awaittanpa ConfigureAwait.
- Tidak
Taskdapat menyelesaikan dalam situasi ini karena hanya selesai ketika asyncmetode selesai; yang asyncmetode dapat tidak lengkap karena mencoba untuk menjadwalkan kelanjutan kepada SynchronizationContext, dan WinForms / WPF / SL / ASP.NET tidak akan mengizinkan kelanjutan untuk menjalankan karena metode sinkron sudah berjalan dalam konteks itu.
Ini adalah salah satu alasan mengapa sebaiknya menggunakan sebanyak mungkin metode ConfigureAwait(false)dalam setiap asyncmetode.
Solusi C
AsyncContext.RunTasktidak akan berfungsi di setiap skenario. Misalnya, jika asyncmetode menunggu sesuatu yang memerlukan acara UI untuk menyelesaikan, maka Anda akan menemui jalan buntu bahkan dengan konteks bersarang. Jika demikian, Anda bisa memulai asyncmetode di kumpulan utas:
var task = Task.Run(async () => await MyAsyncMethod());
var result = task.WaitAndUnwrapException();
Namun, solusi ini membutuhkan MyAsyncMethodyang akan bekerja dalam konteks thread pool. Jadi itu tidak dapat memperbarui elemen UI atau mengakses konteks permintaan ASP.NET. Dan dalam hal ini, Anda mungkin juga menambahkan ConfigureAwait(false)untuk nya awaitpernyataan, dan menggunakan solusi A.
Pembaruan, 2019-05-01: "Praktik terburuk" saat ini ada di artikel MSDN di sini .