Bagikan melalui


Menerapkan Pola Asinkron Berbasis Peristiwa

Jika Anda menulis kelas dengan beberapa operasi yang mungkin menimbulkan penundaan yang nyata, pertimbangkan untuk memberikannya fungsionalitas asinkron dengan menerapkan Pola Asinkron berbasis Peristiwa.

Pola Asinkron berbasis Peristiwa menyediakan cara standar untuk mengemas kelas yang memiliki fitur asinkron. Jika diimplementasikan dengan kelas pembantu seperti AsyncOperationManager, kelas Anda akan berfungsi dengan benar di bawah model aplikasi apa pun, termasuk aplikasi ASP.NET, Konsol, dan Formulir Windows.

Untuk contoh yang mengimplementasikan Pola Asinkron berbasis Peristiwa, lihat Cara: Menerapkan Komponen yang Mendukung Pola Asinkron berbasis Peristiwa.

Untuk operasi asinkron sederhana, Anda mungkin menemukan komponen yang BackgroundWorker cocok. Untuk informasi selengkapnya tentang BackgroundWorker, lihat Cara: Menjalankan Operasi di Latar Belakang.

Daftar berikut menjelaskan fitur Pola Asinkron berbasis Peristiwa yang dibahas dalam topik ini.

  • Peluang untuk Menerapkan Pola Asinkron Berbasis Peristiwa

  • Penamaan Metode Asinkron

  • Mendukung Pembatalan secara Opsional

  • Secara opsional Mendukung Properti IsBusy

  • Secara opsional Berikan Dukungan untuk Pelaporan Kemajuan

  • Secara opsional Berikan Dukungan untuk Mengembalikan Hasil Bertahap

  • Menangani Parameter Out dan Ref dalam Metode

Peluang untuk Menerapkan Pola Asinkron Berbasis Peristiwa

Pertimbangkan untuk menerapkan Pola Asinkron berbasis Peristiwa saat:

  • Klien dari kelas Anda tidak memerlukan objek WaitHandle dan IAsyncResult untuk operasi asinkron, yang berarti polling dan WaitAll atau WaitAny perlu dibangun oleh klien.

  • Anda ingin agar operasi asinkron dikelola klien menggunakan model acara/delegasi yang sudah dikenal.

Setiap operasi adalah kandidat untuk implementasi asinkron, tetapi mereka yang Anda harapkan akan menimbulkan latensi panjang harus dipertimbangkan. Operasi yang paling tepat adalah di mana klien memanggil metode dan diberi tahu tentang penyelesaian, tanpa perlu intervensi lebih lanjut. Juga sesuai adalah operasi yang berjalan terus menerus, secara berkala memberi tahu klien tentang kemajuan, hasil inkremental, atau perubahan status.

Untuk informasi selengkapnya tentang memutuskan kapan harus mendukung Pola Asinkron Berbasis Peristiwa, lihat Memutuskan Kapan Harus Menerapkan Pola Asinkron berbasis Peristiwa.

Penamaan Metode Asinkron

Untuk setiap metode sinkron MethodName yang ingin Anda berikan mitra asinkron:

Tentukan metode MethodNameAsync yang:

  • Menampilkan void.

  • Mengambil parameter yang sama dengan metode MethodName .

  • Menerima beberapa pemanggilan.

Secara opsional tentukan suatu overload MethodNameAsync yang identik dengan MethodNameAsync, tetapi dengan parameter tambahan yang bernilai objek dan disebut userState. Lakukan ini jika Anda siap untuk mengelola beberapa pemanggilan bersamaan metode Anda, dalam hal ini nilai userState akan dikirimkan kembali ke semua penangan kejadian untuk membedakan pemanggilan metode. Anda juga dapat memilih untuk melakukan ini hanya sebagai tempat untuk menyimpan status pengguna untuk pengambilan nanti.

Untuk setiap tanda tangan metode MethodNameAsync terpisah:

  1. Tentukan peristiwa berikut di kelas yang sama dengan metode :

    Public Event MethodNameCompleted As MethodNameCompletedEventHandler
    
    public event MethodNameCompletedEventHandler MethodNameCompleted;
    
  2. Tentukan delegasi berikut dan AsyncCompletedEventArgs. Ini kemungkinan akan didefinisikan di luar kelas itu sendiri, tetapi di namespace yang sama.

    Public Delegate Sub MethodNameCompletedEventHandler( _
        ByVal sender As Object, _
        ByVal e As MethodNameCompletedEventArgs)
    
    Public Class MethodNameCompletedEventArgs
        Inherits System.ComponentModel.AsyncCompletedEventArgs
    Public ReadOnly Property Result() As MyReturnType
    End Property
    
    public delegate void MethodNameCompletedEventHandler(object sender,
        MethodNameCompletedEventArgs e);
    
    public class MethodNameCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs
    {
        public MyReturnType Result { get; }
    }
    
    • Pastikan bahwa kelas MethodNameCompletedEventArgs mengekspos anggotanya sebagai properti baca-saja, dan bukan bidang, karena bidang mencegah pengikatan data.

    • Jangan tentukan kelas turunan apa pun AsyncCompletedEventArgsuntuk metode yang tidak menghasilkan hasil. Cukup gunakan sendiri instans AsyncCompletedEventArgs itu.

      Nota

      Ini sepenuhnya dapat diterima, ketika layak dan sesuai, untuk menggunakan kembali delegasi dan AsyncCompletedEventArgs tipe. Dalam hal ini, penamaan tidak akan sepenuhnya konsisten dengan nama metode, karena baik delegasi tertentu maupun AsyncCompletedEventArgs tidak terikat pada satu metode saja.

Mendukung Pembatalan secara Opsional

Jika kelas Anda akan mendukung pembatalan operasi asinkron, pembatalan harus diekspos ke klien seperti yang dijelaskan di bawah ini. Ada dua poin keputusan yang perlu dicapai sebelum menentukan dukungan pembatalan Anda:

  • Apakah kelas Anda, termasuk penambahan yang diantisipasi di masa mendatang, hanya memiliki satu operasi asinkron yang mendukung pembatalan?
  • Dapatkah operasi asinkron yang mendukung pembatalan mendukung beberapa operasi yang tertunda? Artinya, apakah metode MethodNameAsync mengambil sebuah userState parameter, dan apakah memungkinkan beberapa pemanggilan sebelum menunggu salah satu selesai?

Gunakan jawaban atas dua pertanyaan ini dalam tabel di bawah ini untuk menentukan apa tanda tangan untuk metode pembatalan Anda.

Visual Basic

Beberapa Operasi Simultan Didukung Hanya Satu Operasi pada Satu Waktu
Satu Operasi Asinkron di seluruh kelas Sub MethodNameAsyncCancel(ByVal userState As Object) Sub MethodNameAsyncCancel()
Beberapa Operasi Asinkron di kelas Sub CancelAsync(ByVal userState As Object) Sub CancelAsync()

C#

Beberapa Operasi Simultan Didukung Hanya Satu Operasi pada Satu Waktu
Satu Operasi Asinkron di seluruh kelas void MethodNameAsyncCancel(object userState); void MethodNameAsyncCancel();
Beberapa Operasi Asinkron di kelas void CancelAsync(object userState); void CancelAsync();

Jika Anda menentukan metode CancelAsync(object userState), klien harus berhati-hati ketika memilih nilai status mereka supaya mampu membedakan di antara semua metode asinkron yang dipanggil pada objek, dan bukan hanya semua pemanggilan metode asinkron tunggal.

Keputusan untuk memberi nama versi operasi asinkron tunggal MethodNameAsyncCancel didasarkan pada mampu menemukan metode dengan lebih mudah di lingkungan desain seperti IntelliSense Visual Studio. Ini mengelompokkan anggota terkait dan membedakannya dari anggota lain yang tidak ada hubungannya dengan fungsionalitas asinkron. Jika Anda mengharapkan bahwa mungkin ada operasi asinkron tambahan yang ditambahkan dalam versi berikutnya, lebih baik untuk menentukan CancelAsync.

Jangan tentukan beberapa metode dari tabel di atas di kelas yang sama. Itu tidak akan masuk akal, atau akan mengacaukan antarmuka kelas dengan proliferasi metode.

Metode ini biasanya akan segera kembali, dan operasi mungkin atau mungkin tidak benar-benar membatalkan. Dalam penanganan aktivitas untuk peristiwa MethodNameCompleted , objek MethodNameCompletedEventArgs berisi Cancelled bidang, yang dapat digunakan klien untuk menentukan apakah pembatalan terjadi.

Mematuhi semantik pembatalan yang dijelaskan dalam Praktik Terbaik untuk Menerapkan Pola Asinkron berbasis Peristiwa.

Secara opsional Mendukung Properti IsBusy

Jika kelas Anda tidak mendukung beberapa pemanggilan bersamaan, pertimbangkan untuk mengekspos properti IsBusy. Ini memungkinkan pengembang untuk menentukan apakah metode MethodNameAsync berjalan tanpa menangkap pengecualian dari metode MethodNameAsync .

Mematuhi semantik yang IsBusy dijelaskan dalam Praktik Terbaik untuk Menerapkan Pola Asinkron berbasis Peristiwa.

Secara opsional Berikan Dukungan untuk Pelaporan Kemajuan

Kadang-kadang penting bagi operasi asinkron untuk melaporkan kemajuan selama operasinya. Pola Asinkron berbasis Peristiwa menyediakan pedoman untuk melakukannya.

  • Secara opsional, tentukan peristiwa yang akan dipicu oleh operasi asinkron dan dijalankan pada utas yang sesuai. Objek ProgressChangedEventArgs membawa indikator kemajuan bernilai bilangan bulat yang diharapkan antara 0 dan 100.

  • Beri nama kejadian ini sebagai berikut:

    • ProgressChanged jika kelas memiliki beberapa operasi asinkron (atau diharapkan tumbuh untuk menyertakan beberapa operasi asinkron dalam versi mendatang);

    • MethodNameProgressChanged jika kelas memiliki satu operasi asinkron.

    Pilihan penamaan ini paralel dengan pilihan yang dibuat untuk metode pembatalan yang disebutkan, seperti yang dijelaskan di bagian Mendukung Pembatalan Secara Opsional.

Acara ini harus menggunakan tanda tangan delegate ProgressChangedEventHandler dan kelas ProgressChangedEventArgs. Atau, jika indikator kemajuan yang lebih spesifik untuk domain dapat disediakan (misalnya, byte yang telah dibaca dan total byte untuk operasi pengunduhan), maka Anda harus menentukan kelas turunan dari ProgressChangedEventArgs.

Perhatikan bahwa hanya ada satu ProgressChanged atau peristiwa MethodNameProgressChanged untuk kelas, terlepas dari jumlah metode asinkron yang didukungnya. Klien diharapkan menggunakan userState objek yang diteruskan ke metode MethodNameAsync untuk membedakan antara pembaruan kemajuan pada beberapa operasi bersamaan.

Mungkin ada situasi di mana beberapa operasi memfasilitasi kemajuan dan masing-masing memberikan indikator yang berbeda untuk kemajuan. Dalam hal ini, satu ProgressChanged acara tidaklah tepat, dan Anda mungkin mempertimbangkan mendukung beberapa ProgressChanged acara. Dalam hal ini gunakan pola penamaan MethodNameProgressChanged untuk setiap metode MethodNameAsync .

Mematuhi semantik pelaporan kemajuan yang dijelaskan Praktik Terbaik untuk Menerapkan Pola Asinkron berbasis Peristiwa.

Secara opsional Berikan Dukungan untuk Mengembalikan Hasil Bertahap

Terkadang operasi asinkron dapat mengembalikan hasil inkremental sebelum penyelesaian. Ada sejumlah opsi yang dapat digunakan untuk mendukung skenario ini. Berikut adalah beberapa contoh.

Kelas Operasi Tunggal

Jika kelas Anda hanya mendukung satu operasi asinkron, dan operasi tersebut dapat mengembalikan hasil inkremental, maka:

  • Perluas jenis ProgressChangedEventArgs untuk membawa data hasil inkremental, dan tentukan sebuah peristiwa MethodNameProgressChanged dengan data yang telah diperluas ini.

  • Aktifkan peristiwa MethodNameProgressChanged ini saat ada hasil sementara yang perlu dilaporkan.

Solusi ini berlaku khusus untuk kelas operasi asinkron tunggal karena tidak ada masalah dengan peristiwa yang sama yang terjadi untuk mengembalikan hasil inkremental pada "semua operasi", seperti yang dilakukan peristiwa MethodNameProgressChanged .

Kelas Multi Operasi dengan Hasil Bertahap Homogen

Dalam hal ini, kelas Anda mendukung beberapa metode asinkron, masing-masing mampu mengembalikan hasil bertahap, dan hasil inkremental ini semuanya memiliki jenis data yang sama.

Ikuti model yang dijelaskan di atas untuk kelas operasi tunggal, karena struktur yang sama EventArgs akan berfungsi untuk semua hasil bertahap. Definisikan peristiwa ProgressChanged alih-alih peristiwa MethodNameProgressChanged, karena berlaku untuk beberapa metode asinkron.

Kelas Multi-operasi dengan Hasil Inkremental Heterogen

Jika kelas Anda mendukung beberapa metode asinkron, masing-masing mengembalikan jenis data yang berbeda, Anda harus:

  • Pisahkan pelaporan hasil inkremental Anda dari pelaporan kemajuan Anda.

  • Tentukan peristiwa MethodNameProgressChanged terpisah dengan EventArgs yang sesuai untuk setiap metode asinkron guna menangani data hasil bertahap dari metode tersebut.

Panggil penanganan aktivitas tersebut pada utas yang sesuai seperti yang dijelaskan dalam Praktik Terbaik untuk Menerapkan Pola Asinkron Berbasis Peristiwa.

Menangani Parameter Out dan Ref dalam Metode

Meskipun penggunaan out dan ref , secara umum, tidak disarankan dalam .NET, berikut adalah aturan yang harus diikuti ketika ada:

Diberikan metode sinkron MethodName:

  • out parameter ke MethodName tidak boleh menjadi bagian dari MethodNameAsync. Sebaliknya, mereka harus menjadi bagian dari MethodNameCompletedEventArgs dengan nama yang sama dengan parameternya yang setara dalam MethodName (kecuali ada nama yang lebih sesuai).

  • ref parameter ke MethodName akan muncul sebagai bagian dari MethodNameAsync, dan sebagai bagian dari MethodNameCompletedEventArgs dengan nama yang sama dengan parameternya yang setara dalam MethodName (kecuali ada nama yang lebih sesuai).

Misalnya, jika diberikan:

Public Function MethodName(ByVal arg1 As String, ByRef arg2 As String, ByRef arg3 As String) As Integer
public int MethodName(string arg1, ref string arg2, out string arg3);

Metode asinkron Anda dan kelasnya AsyncCompletedEventArgs akan terlihat seperti ini:

Public Sub MethodNameAsync(ByVal arg1 As String, ByVal arg2 As String)

Public Class MethodNameCompletedEventArgs
    Inherits System.ComponentModel.AsyncCompletedEventArgs
    Public ReadOnly Property Result() As Integer
    End Property
    Public ReadOnly Property Arg2() As String
    End Property
    Public ReadOnly Property Arg3() As String
    End Property
End Class
public void MethodNameAsync(string arg1, string arg2);

public class MethodNameCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs
{
    public int Result { get; };
    public string Arg2 { get; };
    public string Arg3 { get; };
}

Lihat juga