Menangani Reentrancy di Aplikasi Asinkron (Visual Basic)

Ketika Anda menyertakan kode asinkron di aplikasi Anda, Anda harus mempertimbangkan dan mungkin mencegah reentrancy, yang mengacu pada masuknya kembali operasi asinkron sebelum selesai. Jika Anda tidak mengidentifikasi dan menangani kemungkinan untuk reentrancy, itu dapat menyebabkan hasil yang tidak terduga.

Catatan

Untuk menjalankan contoh, Anda harus memiliki Visual Studio 2012 atau yang lebih baru dan .NET Framework 4.5 atau yang lebih baru yang terpasang di komputer Anda.

Catatan

Keamanan Lapisan Transportasi (TLS) versi 1.2 sekarang menjadi versi minimum untuk digunakan dalam pengembangan aplikasi Anda. Jika aplikasi Anda menargetkan versi .NET Framework yang lebih lama dari 4.7, lihat artikel berikut untuk praktik terbaik Keamanan Lapisan Transportasi (TLS) dengan .NET Framework.

Mengenali Reentrancy

Dalam contoh dalam topik ini, pengguna memilih tombol Mulai untuk memulai aplikasi asinkron yang mengunduh serangkaian situs web dan menghitung jumlah total byte yang diunduh. Versi sinkron dari contoh akan merespons dengan cara yang sama terlepas dari berapa kali pengguna memilih tombol karena, setelah pertama kali, utas UI mengabaikan peristiwa tersebut sampai aplikasi selesai berjalan. Namun, dalam aplikasi asinkron, utas UI terus merespons, dan Anda mungkin masuk kembali ke operasi asinkron sebelum selesai.

Contoh berikut menunjukkan output yang diharapkan jika pengguna memilih tombol Mulai hanya sekali. Daftar situs web yang diunduh muncul dengan ukuran, dalam byte, dari setiap situs. Jumlah total byte muncul di akhir.

1. msdn.microsoft.com/library/hh191443.aspx                83732
2. msdn.microsoft.com/library/aa578028.aspx               205273
3. msdn.microsoft.com/library/jj155761.aspx                29019
4. msdn.microsoft.com/library/hh290140.aspx               117152
5. msdn.microsoft.com/library/hh524395.aspx                68959
6. msdn.microsoft.com/library/ms404677.aspx               197325
7. msdn.microsoft.com                                            42972
8. msdn.microsoft.com/library/ff730837.aspx               146159

TOTAL bytes returned:  890591

Namun, jika pengguna memilih tombol lebih dari sekali, penanganan aktivitas dipanggil berulang kali, dan proses pengunduhan dimasukkan kembali setiap kali. Akibatnya, beberapa operasi asinkron berjalan pada saat yang sama, output menjalin hasil, dan jumlah total byte menjadi membingungkan.

1. msdn.microsoft.com/library/hh191443.aspx                83732
2. msdn.microsoft.com/library/aa578028.aspx               205273
3. msdn.microsoft.com/library/jj155761.aspx                29019
4. msdn.microsoft.com/library/hh290140.aspx               117152
5. msdn.microsoft.com/library/hh524395.aspx                68959
1. msdn.microsoft.com/library/hh191443.aspx                83732
2. msdn.microsoft.com/library/aa578028.aspx               205273
6. msdn.microsoft.com/library/ms404677.aspx               197325
3. msdn.microsoft.com/library/jj155761.aspx                29019
7. msdn.microsoft.com                                            42972
4. msdn.microsoft.com/library/hh290140.aspx               117152
8. msdn.microsoft.com/library/ff730837.aspx               146159

TOTAL bytes returned:  890591

5. msdn.microsoft.com/library/hh524395.aspx                68959
1. msdn.microsoft.com/library/hh191443.aspx                83732
2. msdn.microsoft.com/library/aa578028.aspx               205273
6. msdn.microsoft.com/library/ms404677.aspx               197325
3. msdn.microsoft.com/library/jj155761.aspx                29019
4. msdn.microsoft.com/library/hh290140.aspx               117152
7. msdn.microsoft.com                                            42972
5. msdn.microsoft.com/library/hh524395.aspx                68959
8. msdn.microsoft.com/library/ff730837.aspx               146159

TOTAL bytes returned:  890591

6. msdn.microsoft.com/library/ms404677.aspx               197325
7. msdn.microsoft.com                                            42972
8. msdn.microsoft.com/library/ff730837.aspx               146159

TOTAL bytes returned:  890591

Anda dapat meninjau kode yang menghasilkan output ini dengan menggulir ke akhir topik ini. Anda dapat bereksperimen dengan kode dengan mengunduh solusi ke komputer lokal Anda lalu menjalankan proyek WebsiteDownload atau dengan menggunakan kode di akhir topik ini untuk membuat proyek Anda sendiri Untuk informasi dan instruksi selengkapnya, lihat Meninjau dan Menjalankan Aplikasi Contoh.

Menangani Reentrancy

Anda dapat menangani reentrancy dengan berbagai cara, tergantung pada apa yang Anda inginkan untuk dilakukan aplikasi Anda. Topik ini menyajikan contoh berikut:

  • Nonaktifkan Tombol Mulai

    Nonaktifkan tombol Mulai saat operasi berjalan sehingga pengguna tidak dapat mengganggunya.

  • Batalkan dan Mulai Ulang Operasi

    Batalkan operasi apa pun yang masih berjalan saat pengguna memilih tombol Mulai lagi, lalu biarkan operasi yang terakhir diminta berlanjut.

  • Jalankan Beberapa Operasi dan Antre Output

    Izinkan semua operasi yang diminta berjalan secara asinkron, tetapi koordinasikan tampilan output sehingga hasil dari setiap operasi muncul bersama dan berurutan.

Nonaktifkan Tombol Mulai

Anda dapat memblokir tombol Mulai saat operasi berjalan dengan menonaktifkan tombol di bagian StartButton_Click atas penanganan aktivitas. Anda kemudian dapat mengaktifkan kembali tombol dari dalam Finally pemblokiran ketika operasi selesai sehingga pengguna dapat menjalankan aplikasi lagi.

Kode berikut menunjukkan perubahan ini, yang ditandai dengan tanda bintang. Anda dapat menambahkan perubahan pada kode di akhir topik ini, atau Anda dapat mengunduh aplikasi yang sudah jadi dari Sampel Asinkron: Reentrancy di Aplikasi Desktop .NET. Nama proyeknya adalah DisableStartButton.

Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs)
    ' This line is commented out to make the results clearer in the output.
    'ResultsTextBox.Text = ""

    ' ***Disable the Start button until the downloads are complete.
    StartButton.IsEnabled = False

    Try
        Await AccessTheWebAsync()

    Catch ex As Exception
        ResultsTextBox.Text &= vbCrLf & "Downloads failed."
    ' ***Enable the Start button in case you want to run the program again.
    Finally
        StartButton.IsEnabled = True

    End Try
End Sub

Akibat perubahan tersebut, tombol tidak merespons saat AccessTheWebAsync mengunduh situs web, sehingga prosesnya tidak dapat dimasukkan kembali.

Batalkan dan Mulai Ulang Operasi

Alih-alih menonaktifkan tombol Mulai, Anda dapat menjaga tombol tetap aktif tetapi, jika pengguna memilih tombol itu lagi, batalkan operasi yang sudah berjalan dan biarkan operasi yang terakhir dimulai berlanjut.

Untuk informasi selengkapnya tentang pembatalan, lihat Menyempurnakan Aplikasi Asinkron Anda (Visual Basic).

Untuk menyiapkan skenario ini, buat perubahan berikut pada kode dasar yang disediakan dalam Meninjau dan Menjalankan Aplikasi Contoh. Anda juga dapat mengunduh aplikasi yang sudah jadi dari Async Samples: Reentrancy di Aplikasi Desktop .NET. Nama proyek ini adalah CancelAndRestart.

  1. Deklarasikan variabel CancellationTokenSource, cts, yang berada dalam cakupan untuk semua metode.

    Class MainWindow // Or Class MainPage
    
        ' *** Declare a System.Threading.CancellationTokenSource.
        Dim cts As CancellationTokenSource
    
  2. Pada StartButton_Click, tentukan apakah operasi sudah berlangsung. Jika nilai cts adalah Nothing, tidak ada operasi yang sudah aktif. Jika nilainya bukan Nothing, operasi yang sudah berjalan dibatalkan.

    ' *** If a download process is already underway, cancel it.
    If cts IsNot Nothing Then
        cts.Cancel()
    End If
    
  3. Atur cts ke nilai berbeda yang mewakili proses saat ini.

    ' *** Now set cts to cancel the current process if the button is chosen again.
    Dim newCTS As CancellationTokenSource = New CancellationTokenSource()
    cts = newCTS
    
  4. Pada akhir StartButton_Click, proses saat ini selesai, jadi atur nilai cts kembali ke Nothing.

    ' *** When the process completes, signal that another process can proceed.
    If cts Is newCTS Then
        cts = Nothing
    End If
    

Kode berikut menunjukkan semua perubahan dalam StartButton_Click. Penambahan ditandai dengan tanda bintang.

Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs)

    ' This line is commented out to make the results clearer.
    'ResultsTextBox.Text = ""

    ' *** If a download process is underway, cancel it.
    If cts IsNot Nothing Then
        cts.Cancel()
    End If

    ' *** Now set cts to cancel the current process if the button is chosen again.
    Dim newCTS As CancellationTokenSource = New CancellationTokenSource()
    cts = newCTS

    Try
        ' *** Send a token to carry the message if the operation is canceled.
        Await AccessTheWebAsync(cts.Token)

    Catch ex As OperationCanceledException
        ResultsTextBox.Text &= vbCrLf & "Download canceled." & vbCrLf

    Catch ex As Exception
        ResultsTextBox.Text &= vbCrLf & "Downloads failed."
    End Try

    ' *** When the process is complete, signal that another process can proceed.
    If cts Is newCTS Then
        cts = Nothing
    End If
End Sub

Pada AccessTheWebAsync, buat perubahan berikut.

  • Tambahkan parameter untuk menerima token pembatalan dari StartButton_Click.

  • Gunakan metode GetAsync untuk mengunduh situs web karena GetAsync menerima argumen CancellationToken.

  • Sebelum memanggil DisplayResults untuk menampilkan hasil untuk setiap situs web yang diunduh, periksa ct untuk memverifikasi bahwa operasi saat ini tidak dibatalkan.

Kode berikut menunjukkan perubahan ini, yang ditandai dengan tanda bintang.

' *** Provide a parameter for the CancellationToken from StartButton_Click.
Private Async Function AccessTheWebAsync(ct As CancellationToken) As Task

    ' Declare an HttpClient object.
    Dim client = New HttpClient()

    ' Make a list of web addresses.
    Dim urlList As List(Of String) = SetUpURLList()

    Dim total = 0
    Dim position = 0

    For Each url In urlList
        ' *** Use the HttpClient.GetAsync method because it accepts a
        ' cancellation token.
        Dim response As HttpResponseMessage = Await client.GetAsync(url, ct)

        ' *** Retrieve the website contents from the HttpResponseMessage.
        Dim urlContents As Byte() = Await response.Content.ReadAsByteArrayAsync()

        ' *** Check for cancellations before displaying information about the
        ' latest site.
        ct.ThrowIfCancellationRequested()

        position += 1
        DisplayResults(url, urlContents, position)

        ' Update the total.
        total += urlContents.Length
    Next

    ' Display the total count for all of the websites.
    ResultsTextBox.Text &=
        String.Format(vbCrLf & vbCrLf & "TOTAL bytes returned:  " & total & vbCrLf)
End Function

Jika Anda memilih tombol Mulai beberapa kali saat aplikasi ini berjalan, itu harus menghasilkan hasil yang menyerupai output berikut:

1. msdn.microsoft.com/library/hh191443.aspx                83732
2. msdn.microsoft.com/library/aa578028.aspx               205273
3. msdn.microsoft.com/library/jj155761.aspx                29019
4. msdn.microsoft.com/library/hh290140.aspx               122505
5. msdn.microsoft.com/library/hh524395.aspx                68959
6. msdn.microsoft.com/library/ms404677.aspx               197325
Download canceled.

1. msdn.microsoft.com/library/hh191443.aspx                83732
2. msdn.microsoft.com/library/aa578028.aspx               205273
3. msdn.microsoft.com/library/jj155761.aspx                29019
Download canceled.

1. msdn.microsoft.com/library/hh191443.aspx                83732
2. msdn.microsoft.com/library/aa578028.aspx               205273
3. msdn.microsoft.com/library/jj155761.aspx                29019
4. msdn.microsoft.com/library/hh290140.aspx               117152
5. msdn.microsoft.com/library/hh524395.aspx                68959
6. msdn.microsoft.com/library/ms404677.aspx               197325
7. msdn.microsoft.com                                            42972
8. msdn.microsoft.com/library/ff730837.aspx               146159

TOTAL bytes returned:  890591

Untuk menghilangkan daftar parsial, hapus komentar baris pertama kode untuk StartButton_Click menghapus kotak teks setiap kali pengguna memulai ulang operasi.

Jalankan Beberapa Operasi dan Antre Output

Contoh ketiga ini adalah yang paling rumit karena aplikasi memulai operasi asinkron lain setiap kali pengguna memilih tombol Mulai, dan semua operasi berjalan hingga selesai. Semua operasi yang diminta mengunduh situs web dari daftar secara asinkron, tetapi output dari operasi disajikan secara berurutan. Artinya, aktivitas pengunduhan yang sebenarnya diselingi, seperti yang ditunjukkan oleh output dalam Mengenali Reentrancy, tetapi daftar hasil untuk setiap grup disajikan secara terpisah.

Operasi berbagi Taskglobal, pendingWork, yang berfungsi sebagai penjaga gerbang untuk proses tampilan.

Anda dapat menjalankan contoh ini dengan menempelkan perubahan ke dalam kode di Membangun Aplikasi, atau Anda dapat mengikuti instruksi di Mengunduh Aplikasi untuk mengunduh sampel lalu menjalankan proyek QueueResults.

Output berikut menunjukkan hasilnya jika pengguna memilih tombol Mulai hanya sekali. Label huruf, A, menunjukkan bahwa hasilnya adalah dari pertama kali tombol Mulai dipilih. Angka-angka menunjukkan urutan URL dalam daftar target unduhan.

#Starting group A.
#Task assigned for group A.

A-1. msdn.microsoft.com/library/hh191443.aspx                87389
A-2. msdn.microsoft.com/library/aa578028.aspx               209858
A-3. msdn.microsoft.com/library/jj155761.aspx                30870
A-4. msdn.microsoft.com/library/hh290140.aspx               119027
A-5. msdn.microsoft.com/library/hh524395.aspx                71260
A-6. msdn.microsoft.com/library/ms404677.aspx               199186
A-7. msdn.microsoft.com                                            53266
A-8. msdn.microsoft.com/library/ff730837.aspx               148020

TOTAL bytes returned:  918876

#Group A is complete.

Jika pengguna memilih tombol Mulai tiga kali, aplikasi menghasilkan output yang menyerupai baris berikut. Baris informasi yang dimulai dengan tanda pagar (#) melacak kemajuan aplikasi.

#Starting group A.
#Task assigned for group A.

A-1. msdn.microsoft.com/library/hh191443.aspx                87389
A-2. msdn.microsoft.com/library/aa578028.aspx               207089
A-3. msdn.microsoft.com/library/jj155761.aspx                30870
A-4. msdn.microsoft.com/library/hh290140.aspx               119027
A-5. msdn.microsoft.com/library/hh524395.aspx                71259
A-6. msdn.microsoft.com/library/ms404677.aspx               199185

#Starting group B.
#Task assigned for group B.

A-7. msdn.microsoft.com                                            53266

#Starting group C.
#Task assigned for group C.

A-8. msdn.microsoft.com/library/ff730837.aspx               148010

TOTAL bytes returned:  916095

B-1. msdn.microsoft.com/library/hh191443.aspx                87389
B-2. msdn.microsoft.com/library/aa578028.aspx               207089
B-3. msdn.microsoft.com/library/jj155761.aspx                30870
B-4. msdn.microsoft.com/library/hh290140.aspx               119027
B-5. msdn.microsoft.com/library/hh524395.aspx                71260
B-6. msdn.microsoft.com/library/ms404677.aspx               199186

#Group A is complete.

B-7. msdn.microsoft.com                                            53266
B-8. msdn.microsoft.com/library/ff730837.aspx               148010

TOTAL bytes returned:  916097

C-1. msdn.microsoft.com/library/hh191443.aspx                87389
C-2. msdn.microsoft.com/library/aa578028.aspx               207089

#Group B is complete.

C-3. msdn.microsoft.com/library/jj155761.aspx                30870
C-4. msdn.microsoft.com/library/hh290140.aspx               119027
C-5. msdn.microsoft.com/library/hh524395.aspx                72765
C-6. msdn.microsoft.com/library/ms404677.aspx               199186
C-7. msdn.microsoft.com                                            56190
C-8. msdn.microsoft.com/library/ff730837.aspx               148010

TOTAL bytes returned:  920526

#Group C is complete.

Grup B dan grup C dimulai sebelum grup A selesai, tetapi output untuk setiap grup muncul secara terpisah. Semua output untuk grup A muncul terlebih dahulu, diikuti oleh semua output untuk grup B, lalu semua output untuk grup C. Aplikasi ini selalu menampilkan grup secara berurutan dan, untuk setiap grup, selalu menampilkan informasi tentang masing-masing situs web agar URL muncul dalam daftar URL.

Namun, Anda tidak dapat memprediksi urutan di mana unduhan benar-benar terjadi. Setelah beberapa grup dimulai, tugas unduhan yang dihasilkan semuanya aktif. Anda tidak dapat berasumsi bahwa A-1 akan diunduh sebelum B-1, dan Anda tidak dapat berasumsi bahwa A-1 akan diunduh sebelum A-2.

Definisi Global

Kode sampel berisi dua deklarasi global berikut yang dapat terlihat dari semua metode.

Class MainWindow    ' Class MainPage in Windows Store app.

    ' ***Declare the following variables where all methods can access them.
    Private pendingWork As Task = Nothing
    Private group As Char = ChrW(AscW("A") - 1)

Variabel Task, pendingWork, mengawasi proses tampilan dan mencegah grup apa pun mengganggu operasi tampilan grup lain. Variabel karakter, group, melabeli output dari grup yang berbeda untuk memverifikasi bahwa hasil muncul dalam urutan yang diharapkan.

Penanganan Aktivitas Klik

Penanganan aktivitas, StartButton_Click, menaikkan huruf grup setiap kali pengguna memilih tombol Mulai. Kemudian penanganan memanggil AccessTheWebAsync untuk menjalankan operasi pengunduhan.

Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs)
    ' ***Verify that each group's results are displayed together, and that
    ' the groups display in order, by marking each group with a letter.
    group = ChrW(AscW(group) + 1)
    ResultsTextBox.Text &= String.Format(vbCrLf & vbCrLf & "#Starting group {0}.", group)

    Try
        ' *** Pass the group value to AccessTheWebAsync.
        Dim finishedGroup As Char = Await AccessTheWebAsync(group)

        ' The following line verifies a successful return from the download and
        ' display procedures.
        ResultsTextBox.Text &= String.Format(vbCrLf & vbCrLf & "#Group {0} is complete." & vbCrLf, finishedGroup)

    Catch ex As Exception
        ResultsTextBox.Text &= vbCrLf & "Downloads failed."

    End Try
End Sub

Metode AccessTheWebAsync

Contoh ini dibagi AccessTheWebAsync menjadi dua metode. Metode pertama, AccessTheWebAsync, memulai semua tugas unduhan untuk grup dan menyiapkan pendingWork untuk mengontrol proses tampilan. Metode ini menggunakan Language Integrated Query (kueri LINQ) dan ToArray untuk memulai semua tugas unduhan secara bersamaan.

AccessTheWebAsync kemudian memanggil FinishOneGroupAsync untuk menunggu penyelesaian setiap unduhan dan menampilkan panjangnya.

FinishOneGroupAsync mengembalikan tugas yang ditetapkan pada pendingWork dalam AccessTheWebAsync. Nilai itu mencegah gangguan oleh operasi lain sebelum tugas selesai.

Private Async Function AccessTheWebAsync(grp As Char) As Task(Of Char)

    Dim client = New HttpClient()

    ' Make a list of the web addresses to download.
    Dim urlList As List(Of String) = SetUpURLList()

    ' ***Kick off the downloads. The application of ToArray activates all the download tasks.
    Dim getContentTasks As Task(Of Byte())() =
        urlList.Select(Function(addr) client.GetByteArrayAsync(addr)).ToArray()

    ' ***Call the method that awaits the downloads and displays the results.
    ' Assign the Task that FinishOneGroupAsync returns to the gatekeeper task, pendingWork.
    pendingWork = FinishOneGroupAsync(urlList, getContentTasks, grp)

    ResultsTextBox.Text &=
        String.Format(vbCrLf & "#Task assigned for group {0}. Download tasks are active." & vbCrLf, grp)

    ' ***This task is complete when a group has finished downloading and displaying.
    Await pendingWork

    ' You can do other work here or just return.
    Return grp
End Function

Metode FinishOneGroupAsync

Metode ini menelusuri tugas unduhan dalam grup, menunggu masing-masing tugas, menampilkan panjang situs web yang diunduh, dan menambahkan panjang secara keseluruhan.

Pernyataan pertama dalam FinishOneGroupAsync menggunakan pendingWork untuk memastikan bahwa memasukkan metode tidak mengganggu operasi yang sudah dalam proses tampilan atau yang sudah menunggu. Jika operasi seperti itu sedang berlangsung, operasi masuk harus menunggu gilirannya.

Private Async Function FinishOneGroupAsync(urls As List(Of String), contentTasks As Task(Of Byte())(), grp As Char) As Task

    ' Wait for the previous group to finish displaying results.
    If pendingWork IsNot Nothing Then
        Await pendingWork
    End If

    Dim total = 0

    ' contentTasks is the array of Tasks that was created in AccessTheWebAsync.
    For i As Integer = 0 To contentTasks.Length - 1
        ' Await the download of a particular URL, and then display the URL and
        ' its length.
        Dim content As Byte() = Await contentTasks(i)
        DisplayResults(urls(i), content, i, grp)
        total += content.Length
    Next

    ' Display the total count for all of the websites.
    ResultsTextBox.Text &=
        String.Format(vbCrLf & vbCrLf & "TOTAL bytes returned:  " & total & vbCrLf)
End Function

Anda dapat menjalankan contoh ini dengan menempelkan perubahan pada kode dalam Membangun Aplikasi, atau Anda dapat mengikuti instruksi dalam Mengunduh Aplikasi untuk mengunduh sampel, lalu menjalankan proyek QueueResults.

Poin Yang Perlu Diperhatikan

Jalur informasi yang dimulai dengan tanda pagar (#) dalam output yang memperjelas cara kerja contoh ini.

Output menunjukkan pola berikut.

  • Grup dapat dimulai saat grup sebelumnya menampilkan outputnya, tetapi tampilan output grup sebelumnya tidak terganggu.

    #Starting group A.
    #Task assigned for group A. Download tasks are active.
    
    A-1. msdn.microsoft.com/library/hh191443.aspx                87389
    A-2. msdn.microsoft.com/library/aa578028.aspx               207089
    A-3. msdn.microsoft.com/library/jj155761.aspx                30870
    A-4. msdn.microsoft.com/library/hh290140.aspx               119037
    A-5. msdn.microsoft.com/library/hh524395.aspx                71260
    
    #Starting group B.
    #Task assigned for group B. Download tasks are active.
    
    A-6. msdn.microsoft.com/library/ms404677.aspx               199186
    A-7. msdn.microsoft.com                                            53078
    A-8. msdn.microsoft.com/library/ff730837.aspx               148010
    
    TOTAL bytes returned:  915919
    
    B-1. msdn.microsoft.com/library/hh191443.aspx                87388
    B-2. msdn.microsoft.com/library/aa578028.aspx               207089
    B-3. msdn.microsoft.com/library/jj155761.aspx                30870
    
    #Group A is complete.
    
    B-4. msdn.microsoft.com/library/hh290140.aspx               119027
    B-5. msdn.microsoft.com/library/hh524395.aspx                71260
    B-6. msdn.microsoft.com/library/ms404677.aspx               199186
    B-7. msdn.microsoft.com                                            53078
    B-8. msdn.microsoft.com/library/ff730837.aspx               148010
    
    TOTAL bytes returned:  915908
    
  • Tugas pendingWork adalah Nothingpada permulaanFinishOneGroupAsync hanya untuk grup A, yang dimulai terlebih dahulu. Grup A belum menyelesaikan ekspresi tunggu saat mencapai FinishOneGroupAsync. Oleh karena itu, kontrol belum kembali ke AccessTheWebAsync, dan tugas pendingWork pertama belum terjadi.

  • Dua baris berikut selalu muncul bersama-sama dalam output. Kode tidak pernah terputus antara memulai operasi grup di StartButton_Click dan menetapkan tugas untuk grup padapendingWork.

    #Starting group B.
    #Task assigned for group B. Download tasks are active.
    

    Setelah grup memasuki StartButton_Click, operasi tidak menyelesaikan ekspresi tunggu hingga operasi memasuki FinishOneGroupAsync. Oleh karena itu, tidak ada operasi lain yang dapat memperoleh kontrol selama segmen kode tersebut.

Meninjau dan Menjalankan Aplikasi Contoh

Untuk lebih memahami aplikasi contoh, Anda dapat mengunduhnya, membuatnya sendiri, atau meninjau kode di akhir topik ini tanpa menerapkan aplikasi.

Catatan

Untuk menjalankan contoh sebagai aplikasi desktop Windows Presentation Foundation (WPF), Anda harus memiliki Visual Studio 2012 atau yang lebih baru dan .NET Framework 4.5 atau yang lebih baru terpasang pada komputer Anda.

Mengunduh Aplikasi

  1. Unduh file terkompresi dari Sampel Asinkron: Reentrancy di Aplikasi Desktop .NET.

  2. Dekompresi file yang Anda unduh, lalu mulai Visual Studio.

  3. Pada bilah menu, pilih File, Buka, Project/Solusi.

  4. Navigasikan ke folder yang menyimpan kode sampel yang didekompresi, lalu buka file solusi (.sln).

  5. Di Penjelajah Solusi, buka menu pintasan untuk proyek yang ingin Anda jalankan, lalu pilih Atur sebagai StartUpProject.

  6. Pilih tombol CTRL+F5 untuk membangun dan menjalankan proyek.

Membangun Aplikasi

Bagian berikut memberikan kode untuk membangun contoh sebagai aplikasi WPF.

Untuk membangun aplikasi WPF
  1. Mulai Visual Studio.

  2. Di bilah menu, pilih File, Baru, Proyek.

    Kotak dialog Proyek Baru terbuka.

  3. Di panel Templat terpasang, perluas Visual Basic, lalu perluas Windows.

  4. Dalam daftar jenis proyek, pilih Aplikasi WPF.

  5. Beri nama proyek WebsiteDownloadWPF, pilih versi .NET Framework 4.6 atau yang lebih tinggi lalu klik tombol OK.

    Proyek baru muncul di Penjelajah Solusi.

  6. Di editor Visual Studio Code, pilih tab MainWindow.xaml.

    Jika tab tidak terlihat, buka menu pintasan untuk MainWindow.xaml di Penjelajah Solusi, lalu pilih Tampilkan Kode.

  7. Dalam tampilan XAML MainWindow.xaml, ganti kode dengan kode berikut.

    <Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:WebsiteDownloadWPF"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <Grid Width="517" Height="360">
            <Button x:Name="StartButton" Content="Start" HorizontalAlignment="Left" Margin="-1,0,0,0" VerticalAlignment="Top" Click="StartButton_Click" Height="53" Background="#FFA89B9B" FontSize="36" Width="518"  />
            <TextBox x:Name="ResultsTextBox" HorizontalAlignment="Left" Margin="-1,53,0,-36" TextWrapping="Wrap" VerticalAlignment="Top" Height="343" FontSize="10" ScrollViewer.VerticalScrollBarVisibility="Visible" Width="518" FontFamily="Lucida Console" />
        </Grid>
    </Window>
    

    Jendela sederhana yang berisi kotak teks dan tombol muncul dalam tampilan Desain MainWindow.xaml.

  8. Di Penjelajah Solusi, klik kanan Referensi dan pilih Tambahkan Referensi.

    Tambahkan referensi untuk System.Net.Http, jika belum dipilih.

  9. Di Penjelajah Solusi, buka menu pintasan untuk MainWindow.xaml.vb, lalu pilih Tampilkan Kode.

  10. Di MainWindow.xaml.vb , ganti kode dengan kode berikut.

    ' Add the following Imports statements, and add a reference for System.Net.Http.
    Imports System.Net.Http
    Imports System.Threading
    
    Class MainWindow
    
        Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs)
            System.Net.ServicePointManager.SecurityProtocol = System.Net.ServicePointManager.SecurityProtocol Or System.Net.SecurityProtocolType.Tls12
    
            ' This line is commented out to make the results clearer in the output.
            'ResultsTextBox.Text = ""
    
            Try
                Await AccessTheWebAsync()
    
            Catch ex As Exception
                ResultsTextBox.Text &= vbCrLf & "Downloads failed."
    
            End Try
        End Sub
    
        Private Async Function AccessTheWebAsync() As Task
    
            ' Declare an HttpClient object.
            Dim client = New HttpClient()
    
            ' Make a list of web addresses.
            Dim urlList As List(Of String) = SetUpURLList()
    
            Dim total = 0
            Dim position = 0
    
            For Each url In urlList
                ' GetByteArrayAsync returns a task. At completion, the task
                ' produces a byte array.
                Dim urlContents As Byte() = Await client.GetByteArrayAsync(url)
    
                position += 1
                DisplayResults(url, urlContents, position)
    
                ' Update the total.
                total += urlContents.Length
            Next
    
            ' Display the total count for all of the websites.
            ResultsTextBox.Text &=
                String.Format(vbCrLf & vbCrLf & "TOTAL bytes returned:  " & total & vbCrLf)
        End Function
    
        Private Function SetUpURLList() As List(Of String)
            Dim urls = New List(Of String) From
            {
                "https://msdn.microsoft.com/library/hh191443.aspx",
                "https://msdn.microsoft.com/library/aa578028.aspx",
                "https://msdn.microsoft.com/library/jj155761.aspx",
                "https://msdn.microsoft.com/library/hh290140.aspx",
                "https://msdn.microsoft.com/library/hh524395.aspx",
                "https://msdn.microsoft.com/library/ms404677.aspx",
                "https://msdn.microsoft.com",
                "https://msdn.microsoft.com/library/ff730837.aspx"
            }
            Return urls
        End Function
    
        Private Sub DisplayResults(url As String, content As Byte(), pos As Integer)
            ' Display the length of each website. The string format is designed
            ' to be used with a monospaced font, such as Lucida Console or
            ' Global Monospace.
    
            ' Strip off the "http:'".
            Dim displayURL = url.Replace("https://", "")
            ' Display position in the URL list, the URL, and the number of bytes.
            ResultsTextBox.Text &= String.Format(vbCrLf & "{0}. {1,-58} {2,8}", pos, displayURL, content.Length)
        End Sub
    End Class
    
  11. Pilih tombol CTRL+F5 untuk menjalankan program, lalu pilih tombol Mulai beberapa kali.

  12. Buat perubahan dari Nonaktifkan Tombol Mulai, Batalkan dan Mulai Ulang Operasi, atau Jalankan Beberapa Operasi dan Antre Output untuk menangani reentrancy.

Lihat juga