Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
oleh Rick Anderson
Tutorial ini akan mengajari Anda dasar-dasar membangun aplikasi ASP.NET Web Forms asinkron menggunakan Visual Studio Express 2012 untuk Web, yang merupakan versi gratis dari Microsoft Visual Studio. Anda juga dapat menggunakan Visual Studio 2012. Bagian berikut disertakan dalam tutorial ini.
- Bagaimana Permintaan Diproses oleh Kumpulan Utas
- Memilih Metode Sinkron atau Asinkron
- Aplikasi Sampel
- Halaman Sinkron Gizmos
- Membuat Halaman Gizmos Asinkron
- Melakukan Beberapa Operasi secara Paralel
- Menggunakan Token Pembatalan
- Konfigurasi Server untuk Panggilan Layanan Web Konkurensi Tinggi/Latensi Tinggi
Sampel lengkap disediakan untuk tutorial ini di
https://github.com/RickAndMSFT/Async-ASP.NET/ di situs GitHub .
ASP.NET 4.5 Web Pages dalam kombinasi .NET 4.5 memungkinkan Anda mendaftarkan metode asinkron yang mengembalikan objek jenis Tugas. .NET Framework 4 memperkenalkan konsep pemrograman asinkron yang disebut sebagai Tugas dan ASP.NET 4.5 mendukung Tugas. Tugas diwakili oleh jenis Tugas dan jenis terkait di namespace System.Threading.Tasks . .NET Framework 4.5 dibangun pada dukungan asinkron ini dengan kata kunci tunggu dan asinkron yang membuat bekerja dengan objek Tugas jauh lebih kompleks daripada pendekatan asinkron sebelumnya. Kata kunci yang ditunggu adalah singkatan sintaksis untuk menunjukkan bahwa sepotong kode harus secara asinkron menunggu pada beberapa bagian kode lainnya. Kata kunci asinkron mewakili petunjuk yang dapat Anda gunakan untuk menandai metode sebagai metode asinkron berbasis tugas. Kombinasi menunggu, asinkron, dan objek Tugas membuatnya jauh lebih mudah bagi Anda untuk menulis kode asinkron di .NET 4.5. Model baru untuk metode asinkron disebut Pola Asinkron Berbasis Tugas (TAP). Tutorial ini mengasumsikan Anda memiliki beberapa keakraban dengan pemrograman asinkron menggunakan kata kunci tunggu dan asinkron dan namespace layanan Tugas .
Untuk informasi selengkapnya tentang menggunakan kata kunci tunggu dan asinkron dan namespace layanan Tugas , lihat referensi berikut ini.
Bagaimana Permintaan Diproses oleh Kumpulan Utas
Di server web, .NET Framework mempertahankan kumpulan utas yang digunakan untuk melayani permintaan ASP.NET. Ketika permintaan tiba, utas dari kumpulan dikirim untuk memproses permintaan tersebut. Jika permintaan diproses secara sinkron, utas yang memproses permintaan sibuk saat permintaan sedang diproses, dan utas tersebut tidak dapat melayani permintaan lain.
Ini mungkin tidak menjadi masalah, karena kumpulan utas dapat dibuat cukup besar untuk mengakomodasi banyak utas yang sibuk. Namun, jumlah utas di kumpulan utas dibatasi (maksimum default untuk .NET 4.5 adalah 5.000). Dalam aplikasi besar dengan konkurensi permintaan jangka panjang yang tinggi, semua utas yang tersedia mungkin sibuk. Kondisi ini dikenal sebagai kelaparan utas. Ketika kondisi ini tercapai, server web mengantre permintaan. Jika antrean permintaan menjadi penuh, server web menolak permintaan dengan status HTTP 503 (Server Terlalu Sibuk). Kumpulan utas CLR memiliki batasan pada injeksi utas baru. Jika konkurensi bersifat bursty (artinya, situs web Anda bisa tiba-tiba mendapatkan sejumlah besar permintaan) dan semua utas permintaan yang tersedia sibuk karena panggilan backend dengan latensi tinggi, tingkat injeksi utas terbatas dapat membuat aplikasi Anda merespons dengan sangat buruk. Selain itu, setiap utas baru yang ditambahkan ke kumpulan utas memiliki overhead (seperti memori tumpukan 1 MB). Aplikasi web yang menggunakan metode sinkron untuk melayani panggilan latensi tinggi di mana kumpulan utas tumbuh ke maksimum default .NET 4.5 sebesar 5.000 utas akan mengonsumsi sekitar 5 GB lebih banyak memori daripada aplikasi yang dapat melayani permintaan yang sama menggunakan metode asinkron dan hanya 50 utas. Saat Anda melakukan pekerjaan asinkron, Anda tidak selalu menggunakan utas. Misalnya, ketika Anda membuat permintaan layanan web asinkron, ASP.NET tidak akan menggunakan utas apa pun antara panggilan metode asinkron dan menunggu. Menggunakan kumpulan utas untuk melayani permintaan dengan latensi tinggi dapat menyebabkan jejak memori yang besar dan pemanfaatan perangkat keras server yang buruk.
Memproses Permintaan Asinkron
Dalam aplikasi web yang melihat sejumlah besar permintaan bersamaan saat start-up atau memiliki beban bursty (di mana konkurensi meningkat tiba-tiba), membuat panggilan layanan web tidak sinkron akan meningkatkan responsivitas aplikasi Anda. Permintaan asinkron membutuhkan waktu yang sama untuk diproses sebagai permintaan sinkron. Misalnya, jika permintaan melakukan panggilan layanan web yang memerlukan dua detik untuk diselesaikan, permintaan membutuhkan waktu dua detik baik dilakukan secara sinkron atau asinkron. Namun, selama panggilan asinkron, utas tidak diblokir untuk merespons permintaan lain saat menunggu permintaan pertama selesai. Oleh karena itu, permintaan asinkron mencegah antrean permintaan dan pertumbuhan kumpulan utas ketika ada banyak permintaan bersamaan yang memanggil operasi yang berjalan lama.
Memilih Metode Sinkron atau Asinkron
Bagian ini mencantumkan panduan kapan harus menggunakan Metode sinkron atau asinkron. Ini hanyalah panduan; periksa setiap aplikasi satu per satu untuk menentukan apakah metode asinkron membantu performa.
Secara umum, gunakan metode sinkron untuk kondisi berikut:
- Operasinya sederhana atau berjalan singkat.
- Kesederhanaan lebih penting daripada efisiensi.
- Operasi ini terutama merupakan operasi CPU alih-alih operasi yang melibatkan disk ekstensif atau overhead jaringan. Menggunakan metode asinkron pada operasi terikat CPU tidak memberikan manfaat dan menghasilkan lebih banyak overhead.
Secara umum, gunakan metode asinkron untuk kondisi berikut:
Anda memanggil layanan yang dapat dikonsumsi melalui metode asinkron, dan Anda menggunakan .NET 4.5 atau yang lebih tinggi.
Operasi terikat jaringan atau terikat I/O alih-alih terikat CPU.
Paralelisme lebih penting daripada kesederhanaan kode.
Anda ingin menyediakan mekanisme yang memungkinkan pengguna membatalkan permintaan yang berjalan lama.
Ketika manfaat beralih utas melebihi biaya pengalihan konteks. Secara umum, Anda harus membuat metode asinkron jika metode sinkron memblokir utas permintaan ASP.NET saat tidak melakukan pekerjaan. Dengan melakukan panggilan asinkron, utas permintaan ASP.NET tidak diblokir tidak melakukan pekerjaan saat menunggu permintaan layanan web selesai.
Pengujian menunjukkan bahwa operasi pemblokiran adalah hambatan dalam performa situs dan bahwa IIS dapat melayani lebih banyak permintaan dengan menggunakan metode asinkron untuk panggilan pemblokiran ini.
Sampel yang dapat diunduh menunjukkan cara menggunakan metode asinkron secara efektif. Sampel yang disediakan dirancang untuk memberikan demonstrasi sederhana pemrograman asinkron di ASP.NET 4,5. Sampel tidak dimaksudkan untuk menjadi arsitektur referensi untuk pemrograman asinkron dalam ASP.NET. Program sampel memanggil ASP.NET metode Web API yang pada gilirannya memanggil Task.Delay untuk mensimulasikan panggilan layanan web yang berjalan lama. Sebagian besar aplikasi produksi tidak akan menunjukkan manfaat yang jelas untuk menggunakan Metode asinkron.
Beberapa aplikasi mengharuskan semua metode menjadi asinkron. Seringkali, mengonversi beberapa metode sinkron ke metode asinkron memberikan peningkatan efisiensi terbaik untuk jumlah pekerjaan yang diperlukan.
Aplikasi Sampel
Anda dapat mengunduh aplikasi sampel dari https://github.com/RickAndMSFT/Async-ASP.NET situs GitHub . Repositori terdiri dari tiga proyek:
- WebAppAsync: Proyek ASP.NET Web Forms yang menggunakan layanan WebAPIpwg API Web. Sebagian besar kode untuk tutorial ini berasal dari proyek ini.
-
WebAPIpgw: Proyek API Web ASP.NET MVC 4 yang mengimplementasikan
Products, Gizmos and Widgetspengontrol. Ini menyediakan data untuk proyek WebAppAsync dan proyek Mvc4Async . - Mvc4Async: Proyek ASP.NET MVC 4 yang berisi kode yang digunakan dalam tutorial lain. Ini membuat panggilan Web API ke layanan WebAPIpwg .
Halaman Sinkron Gizmos
Kode berikut menunjukkan Page_Load metode sinkron yang digunakan untuk menampilkan daftar gizmos. (Untuk artikel ini, gizmo adalah perangkat mekanis fiktif.)
public partial class Gizmos : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
var gizmoService = new GizmoService();
GizmoGridView.DataSource = gizmoService.GetGizmos();
GizmoGridView.DataBind();
}
}
Kode berikut menunjukkan GetGizmos metode layanan gizmo.
public class GizmoService
{
public async Task<List<Gizmo>> GetGizmosAsync(
// Implementation removed.
public List<Gizmo> GetGizmos()
{
var uri = Util.getServiceUri("Gizmos");
using (WebClient webClient = new WebClient())
{
return JsonConvert.DeserializeObject<List<Gizmo>>(
webClient.DownloadString(uri)
);
}
}
}
Metode ini GizmoService GetGizmos meneruskan URI ke layanan HTTP ASP.NET Web API yang mengembalikan daftar data gizmos. Proyek WebAPIpgw berisi implementasi API gizmos, widget Web dan product pengontrol.
Gambar berikut menunjukkan halaman gizmos dari proyek sampel.
Membuat Halaman Gizmos Asinkron
Sampel menggunakan asinkron baru dan menunggu kata kunci (tersedia di .NET 4.5 dan Visual Studio 2012) untuk memungkinkan pengompilasi bertanggung jawab untuk mempertahankan transformasi rumit yang diperlukan untuk pemrograman asinkron. Pengompilasi memungkinkan Anda menulis kode menggunakan konstruksi alur kontrol sinkron C#dan pengompilasi secara otomatis menerapkan transformasi yang diperlukan untuk menggunakan panggilan balik untuk menghindari pemblokiran utas.
ASP.NET halaman asinkron harus menyertakan direktif Halaman dengan atribut yang Async diatur ke "true". Kode berikut menunjukkan direktif Halaman dengan atribut yang Async diatur ke "true" untuk halaman GizmosAsync.aspx .
<%@ Page Async="true" Language="C#" AutoEventWireup="true"
CodeBehind="GizmosAsync.aspx.cs" Inherits="WebAppAsync.GizmosAsync" %>
Kode berikut menunjukkan Gizmos metode sinkron Page_Load dan GizmosAsync halaman asinkron. Jika browser Anda mendukung elemen tanda> HTML 5<, Anda akan melihat perubahan dalam GizmosAsync sorotan kuning.
protected void Page_Load(object sender, EventArgs e)
{
var gizmoService = new GizmoService();
GizmoGridView.DataSource = gizmoService.GetGizmos();
GizmoGridView.DataBind();
}
Versi asinkron:
protected void Page_Load(object sender, EventArgs e)
{
RegisterAsyncTask(new PageAsyncTask(GetGizmosSvcAsync));
}
private async Task GetGizmosSvcAsync()
{
var gizmoService = new GizmoService();
GizmosGridView.DataSource = await gizmoService.GetGizmosAsync();
GizmosGridView.DataBind();
}
Perubahan berikut diterapkan untuk memungkinkan GizmosAsync halaman menjadi asinkron.
- Direktif Halaman harus memiliki atribut yang
Asyncdiatur ke "true". - Metode
RegisterAsyncTaskini digunakan untuk mendaftarkan tugas asinkron yang berisi kode yang berjalan secara asinkron. - Metode baru
GetGizmosSvcAsyncditandai dengan kata kunci asinkron , yang memberi tahu pengkompilasi untuk menghasilkan panggilan balik untuk bagian isi dan untuk secara otomatis membuatTaskyang dikembalikan. - "Asinkron" ditambahkan ke nama metode asinkron. Menambahkan "Asinkron" tidak diperlukan tetapi merupakan konvensi saat menulis metode asinkron.
- Jenis pengembalian metode baru
GetGizmosSvcAsyncadalahTask. JenisTaskpengembalian mewakili pekerjaan yang sedang berlangsung dan menyediakan pemanggil metode dengan handel untuk menunggu penyelesaian operasi asinkron. - Kata kunci tunggu diterapkan ke panggilan layanan web.
- API layanan web asinkron disebut (
GetGizmosAsync).
Di dalam isi GetGizmosSvcAsync metode metode metode asinkron lain, GetGizmosAsync dipanggil.
GetGizmosAsync segera mengembalikan Task<List<Gizmo>> yang akhirnya akan selesai ketika data tersedia. Karena Anda tidak ingin melakukan hal lain sampai Anda memiliki data gizmo, kode menunggu tugas (menggunakan kata kunci tunggu ). Anda dapat menggunakan kata kunci tunggu hanya dalam metode yang dianotasi dengan kata kunci asinkron .
Kata kunci tunggu tidak memblokir utas hingga tugas selesai. Ini mendaftar sisa metode sebagai panggilan balik pada tugas, dan segera kembali. Ketika tugas yang ditunggu akhirnya selesai, itu akan memanggil panggilan balik tersebut dan dengan demikian melanjutkan eksekusi metode tepat di tempat terakhirnya. Untuk informasi selengkapnya tentang menggunakan kata kunci tunggu dan asinkron dan namespace layanan Tugas , lihat referensi asinkron.
Kode berikut menunjukkan metode GetGizmos dan GetGizmosAsync.
public List<Gizmo> GetGizmos()
{
var uri = Util.getServiceUri("Gizmos");
using (WebClient webClient = new WebClient())
{
return JsonConvert.DeserializeObject<List<Gizmo>>(
webClient.DownloadString(uri)
);
}
}
public async Task<List<Gizmo>> GetGizmosAsync()
{
var uri = Util.getServiceUri("Gizmos");
using (WebClient webClient = new WebClient())
{
return JsonConvert.DeserializeObject<List<Gizmo>>(
await webClient.DownloadStringTaskAsync(uri)
);
}
}
Perubahan asinkron mirip dengan yang dibuat pada GizmosAsync di atas.
- Tanda tangan metode diannotasi dengan kata kunci asinkron , jenis pengembalian diubah menjadi
Task<List<Gizmo>>, dan Asinkron ditambahkan ke nama metode. - Kelas HttpClient asinkron digunakan alih-alih kelas WebClient sinkron.
- Kata kunci tunggu diterapkan ke metode asinkron HttpClientGetAsync .
Gambar berikut menunjukkan tampilan gizmo asinkron.
Presentasi browser data gizmos identik dengan tampilan yang dibuat oleh panggilan sinkron. Satu-satunya perbedaan adalah versi asinkron mungkin lebih berkinerja di bawah beban berat.
Catatan RegisterAsyncTask
Metode yang terhubung dengan RegisterAsyncTask akan berjalan segera setelah PreRender.
Jika Anda menggunakan peristiwa halaman kekosongan asinkron secara langsung, seperti yang ditunjukkan dalam kode berikut:
protected async void Page_Load(object sender, EventArgs e) {
await ...;
// do work
}
Anda tidak lagi memiliki kontrol penuh ketika peristiwa dijalankan. Misalnya, jika .aspx dan . Master mendefinisikan Page_Load peristiwa dan satu atau keduanya asinkron, urutan eksekusi tidak dapat dijamin. Urutan yang tidak ditentukan yang sama untuk penanganan aktivitas (seperti async void Button_Click ) berlaku.
Melakukan Beberapa Operasi secara Paralel
Metode Asinkron memiliki keuntungan signifikan dibandingkan metode sinkron ketika tindakan harus melakukan beberapa operasi independen. Dalam sampel yang disediakan, halaman Sinkron PWG.aspx(untuk Produk, Widget, dan Gizmos) menampilkan hasil tiga panggilan layanan web untuk mendapatkan daftar produk, widget, dan gizmos. Proyek ASP.NET Web API yang menyediakan layanan ini menggunakan Task.Delay untuk mensimulasikan latensi atau panggilan jaringan lambat. Ketika penundaan diatur ke 500 milidetik, halaman PWGasync.aspx asinkron membutuhkan sedikit lebih dari 500 milidetik untuk diselesaikan sementara versi sinkron PWG membutuhkan lebih dari 1.500 milidetik. Halaman PWG.aspx sinkron diperlihatkan dalam kode berikut.
protected void Page_Load(object sender, EventArgs e)
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
var widgetService = new WidgetService();
var prodService = new ProductService();
var gizmoService = new GizmoService();
var pwgVM = new ProdGizWidgetVM(
widgetService.GetWidgets(),
prodService.GetProducts(),
gizmoService.GetGizmos()
);
WidgetGridView.DataSource = pwgVM.widgetList;
WidgetGridView.DataBind();
ProductGridView.DataSource = pwgVM.prodList;
ProductGridView.DataBind();
GizmoGridView.DataSource = pwgVM.gizmoList;
GizmoGridView.DataBind();
stopWatch.Stop();
ElapsedTimeLabel.Text = String.Format("Elapsed time: {0}",
stopWatch.Elapsed.Milliseconds / 1000.0);
}
Kode asinkron PWGasync di belakang ditunjukkan di bawah ini.
protected void Page_Load(object sender, EventArgs e)
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
RegisterAsyncTask(new PageAsyncTask(GetPWGsrvAsync));
stopWatch.Stop();
ElapsedTimeLabel.Text = String.Format("Elapsed time: {0}",
stopWatch.Elapsed.Milliseconds / 1000.0);
}
private async Task GetPWGsrvAsync()
{
var widgetService = new WidgetService();
var prodService = new ProductService();
var gizmoService = new GizmoService();
var widgetTask = widgetService.GetWidgetsAsync();
var prodTask = prodService.GetProductsAsync();
var gizmoTask = gizmoService.GetGizmosAsync();
await Task.WhenAll(widgetTask, prodTask, gizmoTask);
var pwgVM = new ProdGizWidgetVM(
widgetTask.Result,
prodTask.Result,
gizmoTask.Result
);
WidgetGridView.DataSource = pwgVM.widgetList;
WidgetGridView.DataBind();
ProductGridView.DataSource = pwgVM.prodList;
ProductGridView.DataBind();
GizmoGridView.DataSource = pwgVM.gizmoList;
GizmoGridView.DataBind();
}
Gambar berikut menunjukkan tampilan yang dikembalikan dari halaman PWGasync.aspx asinkron.
Menggunakan Token Pembatalan
Metode asinkron yang dikembalikan Taskdapat dibatalkan, yaitu mereka mengambil parameter CancellationToken ketika salah satu disediakan dengan AsyncTimeout atribut arahan Halaman . Kode berikut menunjukkan halaman GizmosCancelAsync.aspx dengan batas waktu pada detik.
<%@ Page Async="true" AsyncTimeout="1"
Language="C#" AutoEventWireup="true"
CodeBehind="GizmosCancelAsync.aspx.cs"
Inherits="WebAppAsync.GizmosCancelAsync" %>
Kode berikut menunjukkan file GizmosCancelAsync.aspx.cs .
protected void Page_Load(object sender, EventArgs e)
{
RegisterAsyncTask(new PageAsyncTask(GetGizmosSvcCancelAsync));
}
private async Task GetGizmosSvcCancelAsync(CancellationToken cancellationToken)
{
var gizmoService = new GizmoService();
var gizmoList = await gizmoService.GetGizmosAsync(cancellationToken);
GizmosGridView.DataSource = gizmoList;
GizmosGridView.DataBind();
}
private void Page_Error(object sender, EventArgs e)
{
Exception exc = Server.GetLastError();
if (exc is TimeoutException)
{
// Pass the error on to the Timeout Error page
Server.Transfer("TimeoutErrorPage.aspx", true);
}
}
Dalam aplikasi sampel yang disediakan, memilih tautan GizmosCancelAsync memanggil halaman GizmosCancelAsync.aspx dan menunjukkan pembatalan (dengan waktu habis) dari panggilan asinkron. Karena waktu penundaan berada dalam rentang acak, Anda mungkin perlu me-refresh halaman beberapa kali untuk mendapatkan pesan kesalahan waktu habis.
Konfigurasi Server untuk Panggilan Layanan Web Konkurensi Tinggi/Latensi Tinggi
Untuk mewujudkan manfaat aplikasi web asinkron, Anda mungkin perlu membuat beberapa perubahan pada konfigurasi server default. Ingatlah hal-hal berikut saat mengonfigurasi dan menekankan pengujian aplikasi web asinkron Anda.
Windows 7, Windows Vista, Window 8, dan semua sistem operasi klien Windows memiliki maksimal 10 permintaan bersamaan. Anda akan memerlukan sistem operasi Windows Server untuk melihat manfaat metode asinkron di bawah beban tinggi.
Daftarkan .NET 4.5 dengan IIS dari prompt perintah yang ditinggikan menggunakan perintah berikut:
%windir%\Microsoft.NET\Framework64 \v4.0.30319\aspnet_regiis -i
Lihat Alat Pendaftaran IIS ASP.NET (Aspnet_regiis.exe)Anda mungkin perlu meningkatkan batas antrean HTTP.sys dari nilai default 1.000 menjadi 5.000. Jika pengaturan terlalu rendah, Anda mungkin melihat HTTP.sys menolak permintaan dengan status HTTP 503. Untuk mengubah batas antrean HTTP.sys:
- Buka manajer IIS dan navigasikan ke panel Kumpulan Aplikasi.
- Klik kanan pada kumpulan aplikasi target dan pilih Pengaturan Tingkat Lanjut.
- Dalam kotak dialog Pengaturan Tingkat Lanjut , ubah Panjang Antrean dari 1.000 menjadi 5.000.
Perhatikan pada gambar di atas, kerangka kerja .NET terdaftar sebagai v4.0, meskipun kumpulan aplikasi menggunakan .NET 4.5. Untuk memahami perbedaan ini, lihat hal berikut:
Penerapan Versi .NET dan Multi-Penargetan - .NET 4.5 adalah peningkatan di tempat ke .NET 4.0
Cara mengatur Aplikasi IIS atau AppPool untuk menggunakan ASP.NET 3.5 daripada 2.0
Jika aplikasi Anda menggunakan layanan web atau System.NET untuk berkomunikasi dengan backend melalui HTTP, Anda mungkin perlu meningkatkan elemen connectionManagement/maxconnection . Untuk aplikasi ASP.NET, ini dibatasi oleh fitur autoConfig hingga 12 kali jumlah CPU. Itu berarti bahwa pada quad-proc, Anda dapat memiliki paling banyak 12 * 4 = 48 koneksi bersamaan ke titik akhir IP. Karena ini terkait dengan autoConfig, cara termampu untuk meningkatkan
maxconnectionaplikasi ASP.NET adalah dengan mengatur System.Net.ServicePointManager.DefaultConnectionLimit secara terprogram dalam metode dariApplication_Startdalam file global.asax . Lihat contoh unduhan untuk contoh.Dalam .NET 4.5, default 5000 untuk MaxConcurrentRequestsPerCPU harus baik-baik saja.