Bagikan melalui


Batalkan Tugas Asinkron yang Tersisa setelah Tugas Selesai (Visual Basic)

Dengan menggunakan Task.WhenAny metode bersama dengan CancellationToken, Anda dapat membatalkan semua tugas yang tersisa ketika satu tugas selesai. Metode WhenAny mengambil argumen yang merupakan kumpulan tugas. Metode ini memulai semua tugas dan mengembalikan satu tugas. Tugas dianggap selesai ketika salah satu tugas dalam koleksi selesai.

Contoh ini menunjukkan cara menggunakan token pembatalan bersama dengan WhenAny untuk menyimpan tugas pertama yang selesai dari kumpulan tugas dan membatalkan tugas-tugas yang tersisa. Setiap tugas mengunduh konten situs web. Contoh menampilkan panjang konten unduhan pertama yang akan diselesaikan dan membatalkan unduhan lainnya.

Nota

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

Mengunduh Contoh

Anda dapat mengunduh proyek Windows Presentation Foundation (WPF) lengkap dari Async Sample: Fine Tuning Your Application lalu ikuti langkah-langkah berikut.

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

  2. Pada bilah menu, pilih File, Buka, Proyek/Solusi.

  3. Dalam kotak dialog Buka Proyek , buka folder yang menyimpan kode sampel yang Anda dekompresi, lalu buka file solusi (.sln) untuk AsyncFineTuningVB.

  4. Di Penjelajah Solusi, buka menu pintasan untuk proyek CancelAfterOneTask , lalu pilih Atur sebagai Proyek StartUp.

  5. Pilih kunci F5 untuk menjalankan proyek.

    Pilih tombol Ctrl+F5 untuk menjalankan proyek tanpa men-debugnya.

  6. Jalankan program beberapa kali untuk memverifikasi bahwa unduhan yang berbeda selesai terlebih dahulu.

Jika Anda tidak ingin mengunduh proyek, Anda dapat meninjau file MainWindow.xaml.vb di akhir topik ini.

Membangun Contoh

Contoh dalam topik ini menambahkan ke proyek yang dikembangkan di Batalkan Tugas Asinkron atau Daftar Tugas untuk membatalkan daftar tugas. Contohnya menggunakan UI yang sama, meskipun tombol Batalkan tidak digunakan secara eksplisit.

Untuk membuat contoh sendiri, langkah demi langkah, ikuti instruksi di bagian "Mengunduh Contoh", tetapi pilih CancelAListOfTasks sebagai Proyek StartUp. Tambahkan perubahan dalam topik ini ke proyek tersebut.

Dalam file MainWindow.xaml.vb dari proyek CancelAListOfTasks , mulai transisi dengan memindahkan langkah-langkah pemrosesan untuk setiap situs web dari perulangan AccessTheWebAsync ke metode asinkron berikut.

' ***Bundle the processing steps for a website into one async method.
Async Function ProcessURLAsync(url As String, client As HttpClient, ct As CancellationToken) As Task(Of Integer)

    ' GetAsync returns a Task(Of HttpResponseMessage).
    Dim response As HttpResponseMessage = Await client.GetAsync(url, ct)

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

    Return urlContents.Length
End Function

Dalam AccessTheWebAsync, contoh ini menggunakan kueri, metode ToArray, dan metode WhenAny untuk membuat dan memulai sekumpulan tugas. Aplikasi WhenAny ke array mengembalikan satu tugas yang, ketika ditunggu, akan menjadi tugas pertama yang menyelesaikan dalam array tugas.

Buat perubahan berikut di AccessTheWebAsync. Tanda bintang menandai perubahan dalam file kode.

  1. Komentari atau hapus perulangan.

  2. Membuat kueri yang, saat dijalankan, menghasilkan kumpulan tugas generik. Setiap panggilan untuk ProcessURLAsync mengembalikan Task<TResult> di mana TResult adalah bilangan bulat.

    ' ***Create a query that, when executed, returns a collection of tasks.
    Dim downloadTasksQuery As IEnumerable(Of Task(Of Integer)) =
        From url In urlList Select ProcessURLAsync(url, client, ct)
    
  3. Panggil ToArray untuk menjalankan kueri dan memulai tugas. WhenAny Aplikasi metode di langkah berikutnya akan menjalankan kueri dan memulai tugas tanpa menggunakan ToArray, tetapi metode lain mungkin tidak. Praktik paling aman adalah memaksa eksekusi kueri secara eksplisit.

    ' ***Use ToArray to execute the query and start the download tasks.
    Dim downloadTasks As Task(Of Integer)() = downloadTasksQuery.ToArray()
    
  4. Panggil WhenAny pada kumpulan tugas. WhenAny mengembalikan Task(Of Task(Of Integer)) atau Task<Task<int>>. Artinya, WhenAny mengembalikan tugas yang dievaluasi ke satu Task(Of Integer) atau Task<int> ketika ditunggu. Tugas tersebut adalah tugas pertama dalam kumpulan yang diselesaikan. Tugas yang selesai terlebih dahulu ditetapkan ke finishedTask. Jenisnya finishedTask adalah Task<TResult> di mana TResult adalah bilangan bulat karena itulah jenis pengembalian .ProcessURLAsync

    ' ***Call WhenAny and then await the result. The task that finishes
    ' first is assigned to finishedTask.
    Dim finishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)
    
  5. Dalam contoh ini, Anda hanya tertarik pada tugas yang selesai terlebih dahulu. Oleh karena itu, gunakan CancellationTokenSource.Cancel untuk membatalkan tugas yang tersisa.

    ' ***Cancel the rest of the downloads. You just want the first one.
    cts.Cancel()
    
  6. Terakhir, tunggu finishedTask untuk mengambil panjang konten yang diunduh.

    Dim length = Await finishedTask
    resultsTextBox.Text &= vbCrLf & $"Length of the downloaded website:  {length}" & vbCrLf
    

Jalankan program beberapa kali untuk memverifikasi bahwa unduhan yang berbeda selesai terlebih dahulu.

Contoh Lengkap

Kode berikut adalah file MainWindow.xaml.vb lengkap atau MainWindow.xaml.cs untuk contoh. Tanda bintang menandai elemen yang ditambahkan untuk contoh ini.

Perhatikan bahwa Anda harus menambahkan referensi untuk System.Net.Http.

Anda dapat mengunduh proyek dari Sampel Asinkron: Menyempurnakan Aplikasi Anda.

' Add an Imports directive and a reference for System.Net.Http.
Imports System.Net.Http

' Add the following Imports directive for System.Threading.
Imports System.Threading

Class MainWindow

    ' Declare a System.Threading.CancellationTokenSource.
    Dim cts As CancellationTokenSource

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

        ' Instantiate the CancellationTokenSource.
        cts = New CancellationTokenSource()

        resultsTextBox.Clear()

        Try
            Await AccessTheWebAsync(cts.Token)
            resultsTextBox.Text &= vbCrLf & "Download complete."

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

        Catch ex As Exception
            resultsTextBox.Text &= vbCrLf & "Download failed." & vbCrLf
        End Try

        ' Set the CancellationTokenSource to Nothing when the download is complete.
        cts = Nothing
    End Sub

    ' You can still include a Cancel button if you want to.
    Private Sub cancelButton_Click(sender As Object, e As RoutedEventArgs)

        If cts IsNot Nothing Then
            cts.Cancel()
        End If
    End Sub

    ' Provide a parameter for the CancellationToken.
    ' Change the return type to Task because the method has no return statement.
    Async Function AccessTheWebAsync(ct As CancellationToken) As Task

        Dim client As HttpClient = New HttpClient()

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

        '' Comment out or delete the loop.
        ''For Each url In urlList
        ''    ' GetAsync returns a Task(Of HttpResponseMessage).
        ''    ' Argument ct carries the message if the Cancel button is chosen.
        ''    ' Note that the Cancel button can cancel all remaining downloads.
        ''    Dim response As HttpResponseMessage = Await client.GetAsync(url, ct)

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

        ''    resultsTextBox.Text &=
        ''        vbCrLf & $"Length of the downloaded string: {urlContents.Length}." & vbCrLf
        ''Next

        ' ***Create a query that, when executed, returns a collection of tasks.
        Dim downloadTasksQuery As IEnumerable(Of Task(Of Integer)) =
            From url In urlList Select ProcessURLAsync(url, client, ct)

        ' ***Use ToArray to execute the query and start the download tasks.
        Dim downloadTasks As Task(Of Integer)() = downloadTasksQuery.ToArray()

        ' ***Call WhenAny and then await the result. The task that finishes
        ' first is assigned to finishedTask.
        Dim finishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)

        ' ***Cancel the rest of the downloads. You just want the first one.
        cts.Cancel()

        ' ***Await the first completed task and display the results
        ' Run the program several times to demonstrate that different
        ' websites can finish first.
        Dim length = Await finishedTask
        resultsTextBox.Text &= vbCrLf & $"Length of the downloaded website:  {length}" & vbCrLf
    End Function

    ' ***Bundle the processing steps for a website into one async method.
    Async Function ProcessURLAsync(url As String, client As HttpClient, ct As CancellationToken) As Task(Of Integer)

        ' GetAsync returns a Task(Of HttpResponseMessage).
        Dim response As HttpResponseMessage = Await client.GetAsync(url, ct)

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

        Return urlContents.Length
    End Function

    ' Add a method that creates a list of web addresses.
    Private Function SetUpURLList() As List(Of String)

        Dim urls = New List(Of String) From
            {
                "https://msdn.microsoft.com",
                "https://msdn.microsoft.com/library/hh290138.aspx",
                "https://msdn.microsoft.com/library/hh290140.aspx",
                "https://msdn.microsoft.com/library/dd470362.aspx",
                "https://msdn.microsoft.com/library/aa578028.aspx",
                "https://msdn.microsoft.com/library/ms404677.aspx",
                "https://msdn.microsoft.com/library/ff730837.aspx"
            }
        Return urls
    End Function

End Class

' Sample output:

' Length of the downloaded website:  158856

' Download complete.

Lihat juga