Bagikan melalui


Gambaran Umum Pola Asinkron Berbasis Peristiwa

Aplikasi yang melakukan banyak tugas secara bersamaan, namun tetap responsif terhadap interaksi pengguna, sering kali memerlukan desain yang menggunakan beberapa utas. Namespace System.Threading menyediakan semua alat yang diperlukan untuk membuat aplikasi multithread berkinerja tinggi, tetapi menggunakan alat-alat ini secara efektif membutuhkan pengalaman yang signifikan dengan rekayasa perangkat lunak multithread. Untuk aplikasi multithread yang relatif sederhana, BackgroundWorker komponen ini menyediakan solusi yang mudah. Untuk aplikasi asinkron yang lebih canggih, pertimbangkan untuk menerapkan kelas yang mematuhi Pola Asinkron berbasis Peristiwa.

Pola Asinkron Berbasis Peristiwa menyediakan keuntungan dari aplikasi multithreaded sambil menyembunyikan banyak isu kompleks yang melekat dalam desain multithreaded. Menggunakan kelas yang mendukung pola ini dapat memungkinkan Anda untuk:

  • Lakukan tugas yang memakan waktu, seperti unduhan dan operasi database, "di latar belakang," tanpa mengganggu aplikasi Anda.

  • Jalankan beberapa operasi secara bersamaan, menerima pemberitahuan ketika setiap selesai.

  • Tunggu hingga sumber daya tersedia tanpa menghentikan ("memblokir") aplikasi Anda.

  • Berkomunikasi dengan operasi asinkron yang tertunda menggunakan model peristiwa dan delegasi yang sudah dikenal. Untuk informasi selengkapnya tentang menggunakan penanganan aktivitas dan delegasi, lihat Peristiwa.

Kelas yang mendukung Pola Asinkron berbasis Peristiwa akan memiliki satu atau beberapa metode bernama MethodNameAsync. Metode ini dapat mencerminkan versi sinkron, yang mana melakukan operasi yang sama pada rangkaian saat ini. Kelas mungkin juga memiliki peristiwa MethodNameCompleted dan mungkin memiliki metode MethodNameAsyncCancel (atau hanya CancelAsync).

PictureBox adalah komponen umum yang mendukung Pola Asinkron berbasis Peristiwa. Anda dapat mengunduh gambar secara sinkron dengan memanggil metodenya Load , tetapi jika gambar besar, atau jika koneksi jaringan lambat, aplikasi Anda akan berhenti merespons sampai operasi pengunduhan selesai dan panggilan untuk Load kembali.

Jika Anda ingin aplikasi terus berjalan saat gambar dimuat, Anda dapat memanggil LoadAsync metode dan menangani LoadCompleted peristiwa, seperti yang akan Anda tangani peristiwa lainnya. Ketika Anda memanggil LoadAsync metode , aplikasi Anda akan terus berjalan saat unduhan berlanjut pada utas terpisah ("di latar belakang"). Penanganan aktivitas Anda akan dipanggil saat operasi pemuatan gambar selesai, dan penanganan aktivitas Anda dapat memeriksa AsyncCompletedEventArgs parameter untuk menentukan apakah pengunduhan berhasil diselesaikan.

Pola Asinkron Berbasis Peristiwa mengharuskan bahwa operasi asinkron dapat dibatalkan, dan PictureBox kontrol mendukung persyaratan ini dengan metode CancelAsync. Panggilan CancelAsync mengirimkan permintaan untuk menghentikan pengunduhan yang tertunda, dan ketika tugas dibatalkan, LoadCompleted acara dinaikkan.

Perhatian

Ada kemungkinan bahwa unduhan akan selesai sama seperti CancelAsync permintaan dibuat, jadi Cancelled mungkin tidak mencerminkan permintaan untuk membatalkan. Ini disebut kondisi balapan dan merupakan masalah umum dalam pemrograman multithreaded. Untuk informasi selengkapnya tentang masalah dalam pemrograman multithreading, lihat Praktik Terbaik Utas Terkelola.

Karakteristik Pola Asinkron Berbasis Peristiwa

Pola Asinkron berbasis Peristiwa mungkin mengambil beberapa bentuk, tergantung pada kompleksitas operasi yang didukung oleh kelas tertentu. Kelas paling sederhana mungkin memiliki satu metode MethodNameAsync dan peristiwa MethodNameCompleted yang sesuai. Kelas yang lebih kompleks mungkin memiliki beberapa metode MethodNameAsync , masing-masing dengan peristiwa MethodNameCompleted yang sesuai, serta versi sinkron dari metode ini. Kelas dapat secara opsional mendukung pembatalan, pelaporan kemajuan, dan hasil inkremental untuk setiap metode asinkron.

Metode asinkron juga dapat mendukung beberapa panggilan yang tertunda (beberapa pemanggilan bersamaan), memungkinkan kode Anda untuk memanggilnya beberapa kali sebelum menyelesaikan operasi lain yang tertunda. Menangani situasi ini dengan benar mungkin mengharuskan aplikasi Anda melacak penyelesaian setiap operasi.

Contoh Pola Asinkron Berbasis Peristiwa

Komponen SoundPlayer dan PictureBox mewakili implementasi sederhana dari Pola Asinkron berbasis Peristiwa. Komponen WebClient dan BackgroundWorker mewakili implementasi yang lebih kompleks dari Pola Asinkron berbasis Peristiwa.

Di bawah ini adalah contoh deklarasi kelas yang sesuai dengan pola:

Public Class AsyncExample  
    ' Synchronous methods.  
    Public Function Method1(ByVal param As String) As Integer
    Public Sub Method2(ByVal param As Double)
  
    ' Asynchronous methods.  
    Overloads Public Sub Method1Async(ByVal param As String)
    Overloads Public Sub Method1Async(ByVal param As String, ByVal userState As Object)
    Public Event Method1Completed As Method1CompletedEventHandler  
  
    Overloads Public Sub Method2Async(ByVal param As Double)
    Overloads Public Sub Method2Async(ByVal param As Double, ByVal userState As Object)
    Public Event Method2Completed As Method2CompletedEventHandler  
  
    Public Sub CancelAsync(ByVal userState As Object)
  
    Public ReadOnly Property IsBusy () As Boolean  
  
    ' Class implementation not shown.  
End Class  
public class AsyncExample  
{  
    // Synchronous methods.  
    public int Method1(string param);  
    public void Method2(double param);  
  
    // Asynchronous methods.  
    public void Method1Async(string param);  
    public void Method1Async(string param, object userState);  
    public event Method1CompletedEventHandler Method1Completed;  
  
    public void Method2Async(double param);  
    public void Method2Async(double param, object userState);  
    public event Method2CompletedEventHandler Method2Completed;  
  
    public void CancelAsync(object userState);  
  
    public bool IsBusy { get; }  
  
    // Class implementation not shown.  
}  

Kelas fiktif AsyncExample memiliki dua metode, yang keduanya mendukung pemanggilan sinkron dan asinkron. Kelebihan beban sinkron berperilaku seperti panggilan metode apa pun dan menjalankan operasi pada utas panggilan; jika operasi memakan waktu, mungkin ada penundaan yang nyata sebelum panggilan kembali. Kelebihan beban asinkron akan memulai operasi pada utas lain dan kemudian segera kembali, memungkinkan utas panggilan berlanjut saat operasi menjalankan "di latar belakang."

Pembebanan Metode Asinkron

Ada kemungkinan dua kelebihan beban untuk operasi asinkron: pemanggilan tunggal dan pemanggilan ganda. Anda dapat membedakan kedua bentuk ini dengan tanda tangan metodenya: formulir pemanggilan ganda memiliki parameter tambahan yang disebut userState. Formulir ini memungkinkan kode Anda untuk memanggil Method1Async(string param, object userState) beberapa kali tanpa menunggu operasi asinkron yang tertunda selesai. Jika, di sisi lain, Anda mencoba memanggil Method1Async(string param) sebelum pemanggilan sebelumnya selesai, metode akan menaikkan InvalidOperationException.

Parameter userState untuk penggunaan ulang variasi multi-pemanggilan memungkinkan Anda membedakan antar operasi yang bersifat asinkron. Anda memberikan nilai unik (misalnya, GUID atau kode hash) untuk setiap panggilan ke Method1Async(string param, object userState), dan ketika setiap operasi selesai, penanganan aktivitas Anda dapat menentukan instans operasi mana yang menaikkan peristiwa penyelesaian.

Melacak Operasi Tertunda

Jika Anda menggunakan overload pemanggilan ganda, kode Anda harus melacak objek userState (ID tugas) untuk tugas yang tertunda. Untuk setiap panggilan ke Method1Async(string param, object userState), Anda biasanya akan menghasilkan objek baru yang unik userState dan menambahkannya ke koleksi. Ketika tugas yang sesuai dengan objek ini userState meningkatkan peristiwa penyelesaian, implementasi metode penyelesaian Anda akan memeriksa AsyncCompletedEventArgs.UserState dan menghapusnya dari koleksi Anda. Digunakan dengan cara ini, userState parameter mengambil peran ID tugas.

Nota

Anda harus berhati-hati untuk memberikan nilai unik pada userState dalam panggilan Anda ke beberapa pemanggilan overload. ID tugas yang tidak unik akan menyebabkan kelas asinkron melempar ArgumentException.

Membatalkan Operasi Tertunda

Penting untuk dapat membatalkan operasi asinkron kapan saja sebelum penyelesaiannya. Kelas yang mengimplementasikan Pola Asinkron berbasis Peristiwa akan memiliki CancelAsync metode (jika hanya ada satu metode asinkron) atau metode MethodNameAsyncCancel (jika ada beberapa metode asinkron).

Metode yang memungkinkan beberapa pemanggilan mengambil userState parameter, yang dapat digunakan untuk melacak masa pakai setiap tugas. CancelAsync mengambil userState parameter, yang memungkinkan Anda membatalkan tugas tertentu yang tertunda.

Metode yang hanya mendukung satu operasi tertunda pada satu waktu, seperti Method1Async(string param), tidak dapat dibatalkan.

Menerima Pembaruan Perkembangan dan Hasil Bertahap

Kelas yang mematuhi Pola Asinkron berbasis Peristiwa dapat secara opsional menyediakan peristiwa untuk melacak kemajuan dan hasil bertambah bertahap. Ini biasanya akan diberi nama ProgressChanged atau MethodNameProgressChanged, dan penanganan aktivitas yang sesuai akan mengambil ProgressChangedEventArgs parameter.

Penangan peristiwa untuk ProgressChanged dapat memeriksa properti ProgressChangedEventArgs.ProgressPercentage untuk menentukan persentase dari tugas asinkron yang sudah diselesaikan. Properti ini akan berkisar dari 0 hingga 100, dan dapat digunakan untuk memperbarui Value properti dari ProgressBar. Jika beberapa operasi asinkron tertunda, Anda dapat menggunakan ProgressChangedEventArgs.UserState properti untuk membedakan operasi mana yang melaporkan kemajuan.

Beberapa kelas mungkin melaporkan hasil inkremental saat operasi asinkron berlangsung. Hasil-hasil ini akan disimpan di kelas yang berasal dari ProgressChangedEventArgs dan hasil ini akan muncul sebagai properti di kelas turunan. Anda dapat mengakses hasil ini di penanganan aktivitas untuk ProgressChanged peristiwa, sama seperti Anda akan mengakses ProgressPercentage properti. Jika beberapa operasi asinkron tertunda, Anda dapat menggunakan UserState properti untuk membedakan operasi mana yang melaporkan hasil inkremental.

Lihat juga