Pencampuran metode sinkronisasi dan async yang efisien dalam satu metode?

11

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/ awaitlebih. Polanya terdiri dari rantai peristiwa berikut:

  1. Menunggu panggilan awal yang memberi saya beberapa informasi yang perlu saya kerjakan
  2. Kerjakan informasi itu secara sinkron
  3. Menunggu panggilan terakhir yang menyimpan pekerjaan yang diperbarui

Blok kode di atas biasanya bagaimana saya menangani metode ini. Saya awaitpanggilan 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 asyncpanggilan, dan keluar dari kultus kargo saya awaititu.

Tetapi apakah ini cara yang paling efisien / benar untuk menangani pola ini? Sepertinya saya bisa melewatkan awaitpanggilan terakhir, tetapi bagaimana jika gagal? Dan haruskah saya menggunakan Taskmetode seperti ContinueWithuntuk 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?

Ditipu
sumber
Menurut saya, kode ini sesingkat dan dapat dimengerti. Apa pun yang bisa saya pikirkan memperkenalkan kompleksitas yang tidak perlu.
Euforia
@ Euphoric: Haruskah saya repot menunggu panggilan terakhir saya? Apa yang akan terjadi jika saya tidak melakukannya dan itu melempar? Apakah akan berbeda seperti saat ini?
Ripped Off

Jawaban:

3

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 penggunaan await, tetapi itu akan membuat kode Anda lebih rumit dan kurang dapat dibaca. Dan itulah intinya await: membuat penulisan kode asinkron lebih sederhana, jika dibandingkan dengan menggunakan kelanjutan.

svick
sumber
0

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 awaitharus 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 Anda Task.Run.

Jadi, untuk penggunaan sumber daya komputasi yang paling efisien, jika RemoveRolesada I / O, itu harus menjadi await RemoveRolesAsyncdan metode I / O yang dipanggil RemoveRolesAsyncjuga 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

Wayne Bloss
sumber
2
Anda seharusnya tidak pernah memecat dan melupakan kode dengan Task.Run. Semua tugas harus ditunggu. Jika Anda tidak menunggu Tugas, dan Tugas tersebut dikumpulkan sampah dalam keadaan di mana pengecualiannya "tidak teramati", itu akan menyebabkan UnobservedTaskException dimunculkan dalam runtime dan dapat menyebabkan crash aplikasi Anda tergantung pada versi kerangka kerja.
Triynko