Oke, kedengarannya aneh, tetapi kodenya sangat sederhana dan menjelaskan situasinya dengan baik.
public virtual async Task RemoveFromRoleAsync(AzureTableUser user, string role)
{
AssertNotDisposed();
var roles = await GetRolesForUser(user);
roles.Roles = RemoveRoles(roles.Roles, role);
await Run(TableOperation.Replace(roles));
}
(Saya tahu saya berbicara semacam abstrak di bawah ini, tetapi di atas adalah metode aktual dari apa yang akan menjadi kode produksi aktual yang benar-benar melakukan apa yang saya tanyakan di sini, dan saya benar-benar tertarik pada Anda sebenarnya meninjau untuk kebenaran vis a vis pola async / wait.)
Saya menghadapi pola ini semakin sering sekarang saya menggunakan async
/ await
lebih. Polanya terdiri dari rantai peristiwa berikut:
- Menunggu panggilan awal yang memberi saya beberapa informasi yang perlu saya kerjakan
- Kerjakan informasi itu secara sinkron
- Menunggu panggilan terakhir yang menyimpan pekerjaan yang diperbarui
Blok kode di atas biasanya bagaimana saya menangani metode ini. Saya await
panggilan pertama, yang harus saya lakukan karena tidak sinkron. Selanjutnya, saya melakukan pekerjaan yang harus saya lakukan yang bukan IO atau sumber daya terikat, dan juga bukan async. Akhirnya, saya menyimpan pekerjaan saya yang juga merupakan async
panggilan, dan keluar dari kultus kargo saya await
itu.
Tetapi apakah ini cara yang paling efisien / benar untuk menangani pola ini? Sepertinya saya bisa melewatkan await
panggilan terakhir, tetapi bagaimana jika gagal? Dan haruskah saya menggunakan Task
metode seperti ContinueWith
untuk menghubungkan kerja sinkron saya dengan panggilan asli? Saya hanya pada satu titik saat ini di mana saya tidak yakin apakah saya menangani ini dengan benar.
Diberikan kode dalam contoh , apakah ada cara yang lebih baik untuk menangani rantai panggilan metode async / sync / async ini?
sumber
Jawaban:
Ya, saya pikir ini adalah cara yang tepat untuk melakukannya.
Anda tidak dapat melewati yang kedua
await
. Jika Anda melakukannya, metode tersebut tampaknya akan selesai terlalu dini (sebelum penghapusan benar-benar dilakukan), dan Anda tidak akan pernah menemukan jika penghapusan gagal.Saya tidak melihat bagaimana
ContinueWith()
hal itu akan membantu di sini. Anda dapat menggunakannya untuk menghindari penggunaanawait
, tetapi itu akan membuat kode Anda lebih rumit dan kurang dapat dibaca. Dan itulah intinyaawait
: membuat penulisan kode asinkron lebih sederhana, jika dibandingkan dengan menggunakan kelanjutan.sumber
Cara untuk menangani pola ini adalah untuk memastikan bahwa semua I / O asinkron. Metode I / O sinkron menyebabkan utas saat ini memblokir sementara menunggu respons dari tujuan I / O (jaringan, sistem file, dll).
Hal lain yang perlu dipertimbangkan adalah yang
await
harus digunakan ketika Anda membutuhkan nilai kembali atau ketika Anda membutuhkan kode yang ditunggu untuk diselesaikan sebelum melakukan sesuatu yang lain. Jika Anda tidak membutuhkan keduanya, Anda dapat "memecat dan melupakan" metode async AndaTask.Run
.Jadi, untuk penggunaan sumber daya komputasi yang paling efisien, jika
RemoveRoles
ada I / O, itu harus menjadiawait RemoveRolesAsync
dan metode I / O yang dipanggilRemoveRolesAsync
juga harus async (dan mungkin ditunggu).Jika kinerja bukan urusan utama Anda, maka boleh saja melakukan I / O sinkron pada utas async. Ini adalah hutang teknis. (Dalam hal ini, Anda mungkin ingin memanggil metode async pertama dengan
ConfigureAwait
, tergantung di mana kode berjalan.)Berikut ini adalah pandangan yang lebih mendalam tentang praktik terbaik - https://msdn.microsoft.com/en-us/magazine/jj991977.aspx
Berikut adalah beberapa catatan tentang perilaku ConfigureAwait di lingkungan yang berbeda seperti ASP.NET, WebAPI, dll - /programming/13489065/best-practice-to-call-confawaw--------ververver-side -kode
sumber