Saya memiliki metode dalam aplikasi ASP.NET, yang menghabiskan cukup banyak waktu untuk menyelesaikannya. Panggilan ke metode ini mungkin terjadi hingga 3 kali selama satu permintaan pengguna, bergantung pada status cache dan parameter yang disediakan pengguna. Setiap panggilan membutuhkan waktu sekitar 1-2 detik. Metodenya sendiri adalah panggilan sinkron ke layanan dan tidak ada kemungkinan untuk mengganti implementasi.
Jadi panggilan sinkron ke layanan terlihat seperti berikut:
public OutputModel Calculate(InputModel input)
{
// do some stuff
return Service.LongRunningCall(input);
}
Dan penggunaan metode ini adalah (perhatikan, pemanggilan metode dapat terjadi lebih dari sekali):
private void MakeRequest()
{
// a lot of other stuff: preparing requests, sending/processing other requests, etc.
var myOutput = Calculate(myInput);
// stuff again
}
Saya mencoba mengubah implementasi dari sisi saya untuk memberikan pekerjaan simultan dari metode ini, dan inilah yang saya sampai sejauh ini.
public async Task<OutputModel> CalculateAsync(InputModel input)
{
return await Task.Run(() =>
{
return Calculate(input);
});
}
Penggunaan (bagian dari kode "lakukan hal lain" berjalan bersamaan dengan panggilan ke layanan):
private async Task MakeRequest()
{
// do some stuff
var task = CalculateAsync(myInput);
// do other stuff
var myOutput = await task;
// some more stuff
}
Pertanyaan saya adalah sebagai berikut. Apakah saya menggunakan pendekatan yang tepat untuk mempercepat eksekusi di aplikasi ASP.NET atau saya melakukan pekerjaan yang tidak perlu mencoba menjalankan kode sinkron secara asinkron? Adakah yang bisa menjelaskan mengapa pendekatan kedua bukanlah pilihan di ASP.NET (jika memang tidak)? Juga, jika pendekatan seperti itu dapat diterapkan, apakah saya perlu memanggil metode tersebut secara asinkron jika itu adalah satu-satunya panggilan yang mungkin kami lakukan saat ini (saya punya kasus seperti itu, ketika tidak ada hal lain yang harus dilakukan sambil menunggu penyelesaian)?
Sebagian besar artikel di internet tentang topik ini mencakup penggunaan async-await
pendekatan dengan kode, yang sudah menyediakan awaitable
metode, tetapi itu bukan kasus saya. Siniadalah artikel bagus yang menjelaskan kasus saya, yang tidak menjelaskan situasi panggilan paralel, menolak opsi untuk membungkus panggilan sinkronisasi, tetapi menurut pendapat saya situasi saya adalah kesempatan untuk melakukannya.
Terima kasih sebelumnya atas bantuan dan tip.
sumber
Task.Run
, konten dijalankan di utas lain, yang diambil dari kumpulan utas. Maka tidak perlu sama sekali untuk membungkus panggilan pemblokiran (seperti panggilan tambang ke layanan) ke dalamRun
s, karena mereka akan selalu menggunakan satu utas masing-masing, yang akan diblokir selama eksekusi metode. Dalam situasi seperti itu, satu-satunya manfaat yang tersisa dariasync-await
kasus saya adalah melakukan beberapa tindakan sekaligus. Tolong, perbaiki saya jika saya salah.Run
(atauParallel
) adalah konkurensi. Operasi masing-masing masih memblokir utas. Karena Anda mengatakan layanan tersebut adalah layanan web, maka saya tidak menyarankan penggunaanRun
atauParallel
; sebagai gantinya, tulis API asinkron untuk layanan tersebut.BeginGetResponse
dan memulai beberapa dari itu, dan kemudian (secara sinkron) memblokir sampai semuanya selesai, tetapi pendekatan semacam ini rumit - lihat blog.stephencleary.com/2012/07/dont-block-on -async-code.html dan msdn.microsoft.com/en-us/magazine/mt238404.aspx . Biasanya lebih mudah dan lebih bersih untuk mengadopsiasync
semua cara, jika memungkinkan.Saya menemukan bahwa kode berikut dapat mengonversi Tugas untuk selalu berjalan secara tidak sinkron
private static async Task<T> ForceAsync<T>(Func<Task<T>> func) { await Task.Yield(); return await func(); }
dan saya telah menggunakannya dengan cara berikut
await ForceAsync(() => AsyncTaskWithNoAwaits())
Ini akan menjalankan Tugas apa pun secara asinkron sehingga Anda dapat menggabungkannya dalam skenario WhenAll, WhenAny, dan penggunaan lainnya.
Anda juga bisa menambahkan Task.Yield () sebagai baris pertama dari kode yang Anda panggil.
sumber