Kapan saya harus menggunakan Async Controllers di ASP.NET MVC?

216

Saya memiliki beberapa masalah dalam menggunakan tindakan async di ASP.NET MVC. Kapan itu meningkatkan kinerja aplikasi saya, dan kapan tidak ?

  1. Apakah baik menggunakan tindakan async di mana saja di ASP.NET MVC?
  2. Mengenai metode yang bisa ditunggu: haruskah saya menggunakan kata kunci async / menunggu ketika saya ingin meminta database (melalui EF / NHibernate / ORM lainnya)?
  3. Berapa kali saya dapat menggunakan kata kunci yang menunggu untuk query database secara tidak sinkron dalam satu metode tindakan tunggal?
Vnuuk
sumber

Jawaban:

109

Metode tindakan asinkron berguna ketika suatu tindakan harus melakukan beberapa operasi jangka panjang yang independen.

Penggunaan khas untuk kelas AsyncController adalah panggilan layanan Web yang sudah berjalan lama.

Haruskah panggilan basis data saya tidak sinkron?

Kumpulan utas IIS sering dapat menangani banyak permintaan pemblokiran yang lebih simultan daripada server basis data. Jika basis data adalah hambatan, panggilan asinkron tidak akan mempercepat respons basis data. Tanpa mekanisme pelambatan, secara efisien mengirimkan lebih banyak pekerjaan ke server database yang kewalahan dengan menggunakan panggilan asinkron hanya memindahkan lebih banyak beban ke database. Jika DB Anda adalah penghambat, panggilan asinkron tidak akan menjadi peluru ajaib.

Anda harus melihat referensi 1 dan 2

Berasal dari @PanagiotisKanavos komentar:

Selain itu, async tidak berarti paralel. Eksekusi asinkron membebaskan threadpool thread berharga dari pemblokiran untuk sumber daya eksternal, tanpa biaya kerumitan atau kinerja. Ini berarti mesin IIS yang sama dapat menangani lebih banyak permintaan bersamaan, bukan karena itu akan berjalan lebih cepat.

Anda juga harus mempertimbangkan bahwa pemblokiran panggilan dimulai dengan spin-intensif CPU. Selama masa-masa stres, pemblokiran panggilan akan menyebabkan penundaan yang meningkat dan daur ulang kumpulan aplikasi. Panggilan asinkron hanya menghindari ini

Tharif
sumber
27
Mengenai async, IIS dan database, posting blog sangat tua dan kesimpulan yang diambil di sini salah. IIS memiliki server yang memuat jauh lebih besar daripada basis data, utas threadpool terbatas dan antrian permintaan panjang dapat menghasilkan 500. Apa pun yang membebaskan utas sambil menunggu IO bermanfaat. Bahkan tautannya bukan tentang apa yang diminta OP. Bahkan penulis yang sama telah menulis bahwa Anda harus menggunakan metode DB asinkron di mana pun Anda bisa
Panagiotis Kanavos
30
Selain itu, async tidak berarti paralel. Eksekusi asinkron membebaskan threadpool thread berharga dari pemblokiran untuk sumber daya eksternal, tanpa biaya kerumitan atau kinerja. Ini berarti mesin IIS yang sama dapat menangani lebih banyak permintaan bersamaan, bukan karena itu akan berjalan lebih cepat.
Panagiotis Kanavos
5
Anda juga harus mempertimbangkan bahwa pemblokiran panggilan dimulai dengan spin-intensif CPU. Selama masa-masa stres, pemblokiran panggilan akan menyebabkan penundaan yang meningkat dan daur ulang kumpulan aplikasi. Panggilan asinkron hanya menghindari ini
Panagiotis Kanavos
1
Karena ini adalah jawaban yang diterima dan dengan demikian di atas bagi kebanyakan orang, mungkin bijaksana untuk menghapus paragraf pertama kedua tentang waktu eksekusi dan berjalan secara paralel, yang tidak ada hubungannya dengan async. Saya menyadari ada catatan di akhir, tetapi ini cukup menyesatkan.
Rob
1
Eksekusi asynchronous membebaskan utas hanya dalam kasus-kasus ketika async benar-benar turun ke bagian paling bawah dari implementasi dan menggunakan beberapa mekanisme panggilan balik untuk memberi sinyal kesiapan dan untuk memutar utas baru untuk mengubah konteks dan memproses hasilnya. Jadi, saya tidak yakin dalam kasus apa pengalihan konteks / pembuatan utas baru ini lebih efisien daripada hanya menunggu hasil dalam satu utas? Panggilan layanan web yang sudah lama berjalan adalah ide yang buruk, saya lebih memilih untuk menurunkannya ke layanan latar belakang yang andal dan membiarkan klien memeriksa hasilnya, yang mungkin datang dalam beberapa menit, jam atau hari.
JustAMartin
229

Anda mungkin menemukan artikel MSDN saya pada subjek bermanfaat ; Saya mengambil banyak ruang dalam artikel yang menjelaskan kapan Anda harus menggunakan asyncASP.NET, bukan hanya bagaimana menggunakannya asyncdi ASP.NET.

Saya memiliki beberapa masalah dalam menggunakan tindakan async di ASP.NET MVC. Ketika itu meningkatkan kinerja aplikasi saya, dan kapan - tidak.

Pertama, memahami bahwa async/ awaitadalah semua tentang membebaskan benang . Pada aplikasi GUI, ini terutama tentang membebaskan utas GUI sehingga pengalaman pengguna lebih baik. Pada aplikasi server (termasuk ASP.NET MVC), ini terutama tentang membebaskan utas permintaan sehingga server dapat menskala.

Secara khusus, itu tidak akan:

  • Buat permintaan pribadi Anda selesai lebih cepat. Bahkan, mereka akan menyelesaikan (hanya sedikit sedikit) lebih lambat.
  • Kembali ke pemanggil / browser saat Anda menekan sebuah await. awaithanya "hasil" ke kumpulan thread ASP.NET, bukan ke browser.

Pertanyaan pertama adalah - apakah baik menggunakan tindakan async di ASP.NET MVC?

Saya akan mengatakan itu baik untuk menggunakannya di mana pun Anda melakukan I / O. Ini mungkin belum tentu bermanfaat (lihat di bawah).

Namun, buruk untuk menggunakannya untuk metode yang terikat CPU. Terkadang para pengembang berpikir mereka bisa mendapatkan manfaat asyncdengan hanya memanggil Task.Runpengendali mereka, dan ini adalah ide yang mengerikan. Karena kode itu akhirnya membebaskan utas permintaan dengan mengambil utas lainnya, jadi tidak ada untungnya sama sekali (dan pada kenyataannya, mereka menerima penalti dari sakelar utas ekstra)!

Haruskah saya menggunakan kata kunci async / menunggu ketika saya ingin query database (melalui EF / NHibernate / ORM lainnya)?

Anda dapat menggunakan metode apa pun yang Anda tunggu tersedia. Saat ini sebagian besar pemain utama mendukung async, tetapi ada beberapa yang tidak. Jika ORM Anda tidak mendukung async, maka jangan mencoba untuk membungkusnya Task.Runatau semacamnya (lihat di atas).

Perhatikan bahwa saya berkata "Anda bisa menggunakan". Jika Anda berbicara tentang ASP.NET MVC dengan backend database tunggal, maka Anda (hampir pasti) tidak akan mendapatkan manfaat skalabilitas dari async. Ini karena IIS dapat menangani permintaan yang jauh lebih konkuren daripada satu contoh SQL server (atau RDBMS klasik lainnya). Namun, jika backend Anda lebih modern - cluster SQL server, Azure SQL, NoSQL, dll - dan backend Anda bisa menskalakan, dan bottleneck skalabilitas Anda adalah IIS, maka Anda bisa mendapatkan manfaat skalabilitas dari async.

Pertanyaan ketiga - Berapa kali saya dapat menggunakan kata kunci menunggu untuk query database secara tidak sinkron dalam SATU metode tindakan tunggal?

Sebanyak yang Anda suka. Namun, perhatikan bahwa banyak ORM memiliki aturan satu operasi per koneksi. Secara khusus, EF hanya mengizinkan satu operasi per DbContext; ini benar apakah operasi itu sinkron atau asinkron.

Juga, ingatlah skalabilitas backend Anda lagi. Jika Anda menekan satu contoh SQL Server, dan IIS Anda sudah mampu menjaga SQLServer pada kapasitas penuh, maka menggandakan atau tiga kali lipat tekanan pada SQLServer tidak akan membantu Anda sama sekali.

Stephen Cleary
sumber
2
@seebiscuit: Saat melakukan I / O (asynchronous yang tepat), tidak ada utas yang digunakan. Saya memiliki posting blog yang lebih detail.
Stephen Cleary
2
Berapa banyak permintaan yang dapat ditangani IIS dan satu contoh SQL Server? Bagaimana saya bisa menemukan angka-angka ini?
MOD
1
@MOD: Tergantung konfigurasi dan perangkat kerasnya. Satu-satunya cara untuk menemukan angka-angka ini adalah dengan melakukan tes beban di server Anda sendiri.
Stephen Cleary
1
@Flezcano: Metode yang mengeksekusi sepenuhnya pada CPU. Yaitu, mereka tidak melakukan I / O atau memblokir.
Stephen Cleary
1
Maaf pak tetapi SO tidak akan menerima pertanyaan 2 liner ini yang saya coba pahami. Ketika saya sedang meneliti untuk hal ini seperti jika saya memiliki 1 titik akhir web api yang dipanggil oleh 1000 pengguna pada saat yang sama maka titik akhir ini akan dapat ke server masing-masing dari seribu permintaan ini atau saya harus membuatnya async untuk menangani 1000 permintaan?
Learning-Overthinker-Confused
21

apakah itu baik untuk menggunakan tindakan async di mana saja di ASP.NET MVC?

Seperti biasa dalam pemrograman, itu tergantung . Selalu ada trade-off ketika menuruni jalan tertentu.

async-awaitbersinar di tempat-tempat di mana Anda tahu Anda akan menerima permintaan bersamaan untuk layanan Anda dan Anda ingin dapat mengukur dengan baik. Bagaimana cara async-awaitmembantu meningkatkan skala? Pada kenyataan bahwa ketika Anda memanggil panggilan Iyn async secara serempak , seperti panggilan jaringan atau memukul basis data Anda, utas saat ini yang bertanggung jawab atas eksekusi diblokir menunggu permintaan untuk selesai. Ketika Anda menggunakan async-await, Anda mengaktifkan kerangka kerja untuk membuat mesin keadaan untuk Anda yang memastikan bahwa setelah panggilan IO selesai, metode Anda terus mengeksekusi dari tempat itu ditinggalkan.

Satu hal yang perlu diperhatikan adalah mesin state ini memiliki overhead yang halus. Membuat metode asinkron tidak membuatnya mengeksekusi lebih cepat , dan itu merupakan faktor penting untuk dipahami dan kesalahpahaman yang dimiliki banyak orang.

Hal lain yang perlu dipertimbangkan ketika menggunakan async-awaitadalah fakta bahwa async sepenuhnya , artinya Anda akan melihat async menembus seluruh tumpukan panggilan Anda, paling atas di buttom. Ini berarti bahwa jika Anda ingin mengekspos API sinkron, Anda akan sering mendapati diri Anda menduplikasi sejumlah kode tertentu, karena async dan sinkronisasi tidak tercampur dengan baik.

Haruskah saya menggunakan kata kunci async / menunggu ketika saya ingin query database (melalui EF / NHibernate / ORM lainnya)?

Jika Anda memilih untuk menggunakan jalur panggilan Iync async, maka ya, async-awaitakan menjadi pilihan yang baik, karena semakin banyak penyedia basis data modern mengekspos metode async menerapkan TAP (Pola Tugas Asinkron).

Berapa kali saya dapat menggunakan kata kunci menunggu untuk query database secara serempak dalam SATU metode tindakan tunggal?

Sebanyak yang Anda inginkan, selama Anda mengikuti aturan yang dinyatakan oleh penyedia basis data Anda. Tidak ada batasan jumlah panggilan async yang dapat Anda lakukan. Jika Anda memiliki kueri yang independen satu sama lain dan dapat dibuat secara bersamaan, Anda dapat memutar tugas baru untuk masing-masing dan menggunakan await Task.WhenAlluntuk menunggu keduanya selesai.

Yuval Itzchakov
sumber
2
Panggilan db asinkron tidak mengeksekusi lebih cepat tetapi memungkinkan mesin IIS yang sama ke server banyak lagi permintaan karena utas threadpool tidak terbuang. Ini juga menurunkan biaya CPU karena pemblokiran panggilan sebenarnya dimulai dengan putaran-intensif CPU sebelum benar-benar memblokir. Dalam situasi beban tinggi ini dapat menjadi perbedaan antara mesin yang mengalami kesulitan atau gagal dan daur ulang
Panagiotis Kanavos
@PanagiotisKanavos saya tahu, apakah itu tidak jelas dari apa yang saya katakan?
Yuval Itzchakov
1
Jawaban Anda tidak menyebutkan spesifikasi IIS - skenario krisis / daur ulang adalah alasan utama untuk menggunakan async secara keseluruhan. Seseorang yang belum mengalaminya mungkin tidak akan mengerti scale out wellartinya your server won't die under load. Atau mungkin kasusonce burned ...
Panagiotis Kanavos
7

5 sen saya:

  1. Gunakan async/awaitjika dan hanya jika Anda melakukan operasi IO, seperti DB atau layanan web layanan eksternal.
  2. Selalu lebih suka panggilan async ke DB.
  3. Setiap kali Anda menanyakan DB.

PS Ada kasus luar biasa untuk poin 1, tetapi Anda harus memiliki pemahaman yang baik tentang async internal untuk ini.

Sebagai keuntungan tambahan, Anda dapat melakukan beberapa panggilan IO secara paralel jika diperlukan:

Task task1 = FooAsync(); // launch it, but don't wait for result
Task task2 = BarAsync(); // launch bar; now both foo and bar are running
await Task.WhenAll(task1, task2); // this is better in regard to exception handling
// use task1.Result, task2.Result
bohdan_trotsenko
sumber
6

asynctindakan sangat membantu ketika tindakan melakukan beberapa operasi I \ O ke DB atau beberapa panggilan yang terikat jaringan di mana utas yang memproses permintaan akan terhenti sebelum mendapat jawaban dari DB atau panggilan yang terikat jaringan yang baru saja Anda panggil. Sebaiknya Anda menggunakan menunggu dengan mereka dan itu benar-benar akan meningkatkan respon aplikasi Anda (karena lebih sedikit thread input ASP \ output akan terhenti sambil menunggu DB atau operasi lain seperti itu). Dalam semua aplikasi saya setiap kali banyak panggilan ke DB sangat diperlukan saya selalu membungkusnya dengan metode awaiatable dan menyebutnya dengan awaitkata kunci.

Dimitri
sumber
5

Seperti yang Anda ketahui, MVC mendukung pengontrol asinkron dan Anda harus memanfaatkannya. Jika Controller Anda, melakukan operasi yang panjang, (mungkin berbasis disk I / o atau panggilan jaringan ke layanan jarak jauh lain), jika permintaan ditangani secara sinkron, utas IIS sibuk sepanjang waktu. Akibatnya, utas hanya menunggu operasi yang panjang selesai. Ini dapat digunakan dengan lebih baik dengan melayani permintaan lain sementara operasi yang diminta terlebih dahulu sedang dalam proses. Ini akan membantu dalam melayani lebih banyak permintaan bersamaan. Layanan web Anda akan sangat skalabel dan tidak akan dengan mudah mengalami masalah C10k . Sebaiknya gunakan async / tunggu untuk permintaan db. dan ya Anda dapat menggunakannya sebanyak yang Anda anggap cocok.

Lihatlah di sini untuk saran yang sangat baik.

anurag
sumber
3

Pengalaman saya adalah bahwa hari ini banyak pengembang menggunakan async/awaitsebagai default untuk pengendali.

Saran saya adalah, gunakan hanya ketika Anda tahu itu akan membantu Anda .

Alasannya, seperti yang telah disebutkan oleh Stephen Cleary dan yang lain, itu dapat memperkenalkan masalah kinerja, bukan menyelesaikannya, dan itu akan membantu Anda hanya dalam skenario tertentu:

  • Pengontrol lalu lintas tinggi
  • Backend yang bisa diukur
gajama
sumber
2

Apakah baik menggunakan tindakan async di mana saja di ASP.NET MVC?

Adalah baik untuk melakukannya di mana pun Anda dapat menggunakan metode async terutama ketika Anda memiliki masalah kinerja di tingkat proses pekerja yang terjadi untuk data besar dan operasi perhitungan. Kalau tidak, tidak perlu karena unit testing akan perlu casting.

Mengenai metode yang bisa ditunggu: haruskah saya menggunakan kata kunci async / menunggu ketika saya ingin meminta database (melalui EF / NHibernate / ORM lainnya)?

Ya, lebih baik menggunakan async untuk setiap operasi DB sebisa mungkin untuk menghindari masalah kinerja di tingkat proses pekerja. Perhatikan bahwa EF telah menciptakan banyak alternatif async untuk sebagian besar operasi, seperti:

.ToListAsync()
.FirstOrDefaultAsync()
.SaveChangesAsync()
.FindAsync()

Berapa kali saya dapat menggunakan kata kunci yang menunggu untuk query database secara tidak sinkron dalam satu metode tindakan tunggal?

Langit adalah batasnya

Shadi Namrouti
sumber
Logika bisnis untuk sebagian besar aplikasi web biasanya memerlukan operasi yang sangat berurutan, sehingga beralih antara proses paralel dalam kebanyakan kasus hanya dapat dilakukan pada tingkat paling atas dari manajemen proses permintaan web / pekerja, yang tidak menangani permintaan basis data secara langsung. Saya benar-benar ingin melihat beberapa contoh dunia nyata dari aplikasi web tipikal di mana sebenarnya merupakan ide yang baik untuk memproses permintaan DB dengan cara async.
JustAMartin