Saya mencoba menggunakan async/await
fitur ASP.NET dalam proyek API Web saya. Saya tidak begitu yakin apakah itu akan membuat perbedaan dalam kinerja layanan API Web saya. Temukan di bawah alur kerja dan kode contoh dari aplikasi saya.
Alur Kerja:
Aplikasi UI → Titik akhir API Web (pengontrol) → Metode panggilan di lapisan layanan API Web → Panggil layanan web eksternal lainnya. (Di sini kita memiliki interaksi DB, dll.)
Pengontrol:
public async Task<IHttpActionResult> GetCountries()
{
var allCountrys = await CountryDataService.ReturnAllCountries();
if (allCountrys.Success)
{
return Ok(allCountrys.Domain);
}
return InternalServerError();
}
Lapisan Layanan:
public Task<BackOfficeResponse<List<Country>>> ReturnAllCountries()
{
var response = _service.Process<List<Country>>(BackOfficeEndpoint.CountryEndpoint, "returnCountries");
return Task.FromResult(response);
}
Saya menguji kode di atas dan berfungsi. Tapi saya tidak yakin apakah itu penggunaan yang benar async/await
. Silakan bagikan pemikiran Anda.
Jawaban:
Ingatlah bahwa manfaat utama kode asinkron di sisi server adalah skalabilitas . Ini tidak akan secara ajaib membuat permintaan Anda berjalan lebih cepat. Saya membahas beberapa
async
pertimbangan "harus saya gunakan " dalam artikelasync
saya di ASP.NET .Saya pikir kasus penggunaan Anda (memanggil API lain) sangat sesuai untuk kode asinkron, ingatlah bahwa "asinkron" tidak berarti "lebih cepat". Pendekatan terbaik adalah pertama-tama membuat UI Anda responsif dan asinkron; ini akan membuat aplikasi Anda terasa lebih cepat meskipun sedikit lebih lambat.
Sejauh kode berjalan, ini tidak asinkron:
Anda memerlukan implementasi yang benar-benar asinkron untuk mendapatkan manfaat skalabilitas dari
async
:Atau (jika logika Anda dalam metode ini benar-benar hanya sebuah pass-through):
Perhatikan bahwa lebih mudah untuk bekerja dari "dalam ke luar" daripada "dari luar ke dalam" seperti ini. Dengan kata lain, jangan mulai dengan tindakan pengontrol asinkron lalu paksa metode hilir menjadi asinkron. Sebagai gantinya, identifikasi operasi asinkron secara alami (memanggil API eksternal, kueri database, dll), dan buat yang asinkron di tingkat paling bawah terlebih dahulu (
Service.ProcessAsync
). Kemudian biarkanasync
menetes, membuat tindakan pengontrol Anda asinkron sebagai langkah terakhir.Dan dalam keadaan apa pun Anda tidak boleh menggunakan
Task.Run
dalam skenario ini.sumber
Itu benar, tapi mungkin tidak berguna.
Karena tidak ada yang perlu ditunggu - tidak ada panggilan untuk memblokir API yang dapat beroperasi secara asinkron - maka Anda menyiapkan struktur untuk melacak operasi asinkron (yang memiliki overhead) tetapi kemudian tidak memanfaatkan kemampuan itu.
Misalnya, jika lapisan layanan melakukan operasi DB dengan Entity Framework yang mendukung panggilan asinkron:
Anda akan mengizinkan utas pekerja untuk melakukan sesuatu yang lain saat db dikueri (dan dengan demikian dapat memproses permintaan lain).
Await cenderung menjadi sesuatu yang perlu dilakukan sepenuhnya: sangat sulit untuk menyesuaikan diri dengan sistem yang ada.
sumber
Anda tidak memanfaatkan async / await secara efektif karena utas permintaan akan diblokir saat menjalankan sinkronisasi metode
ReturnAllCountries()
Utas yang ditugaskan untuk menangani permintaan akan menunggu sebentar
ReturnAllCountries()
itu berfungsi.Jika Anda dapat menerapkan
ReturnAllCountries()
menjadi asinkron, Anda akan melihat manfaat skalabilitas. Ini karena utas dapat dilepaskan kembali ke kumpulan utas .NET untuk menangani permintaan lain, saatReturnAllCountries()
sedang mengeksekusi. Ini akan memungkinkan layanan Anda memiliki throughput yang lebih tinggi, dengan memanfaatkan utas secara lebih efisien.sumber
Saya akan mengubah lapisan layanan Anda menjadi:
seperti yang Anda miliki, Anda masih menjalankan
_service.Process
panggilan Anda secara serempak, dan mendapatkan sedikit atau tidak ada manfaat dari menunggunya.Dengan pendekatan ini, Anda membungkus panggilan yang berpotensi lambat dalam
Task
, memulainya, dan mengembalikannya untuk ditunggu. Sekarang Anda mendapatkan keuntungan dari menungguTask
.sumber
Service
bukan metode asinkron, dan tidak sedang menunggu dalamService
panggilan itu sendiri. Saya bisa mengerti maksudnya, tapi saya tidak percaya itu berlaku di sini.Task.Run
harus dihindari di ASP.NET. Pendekatan ini akan menghapus semua manfaat dariasync
/await
dan benar-benar berperforma lebih buruk saat dimuat daripada hanya panggilan sinkron.