Aracılığıyla paylaş


Nasıl Yapılır: Task.WhenAll Kullanarak Asenkron Kılavuzu Genişletme (Visual Basic)

Zaman uyumsuz çözümün performansını, İzlenecek Yol: Zaman Uyumsuz ve Await Kullanarak Web'e Erişme (Visual Basic) bölümünde Task.WhenAll yöntemini kullanarak geliştirebilirsiniz. Bu yöntem, görev koleksiyonu olarak temsil edilen birden çok zaman uyumsuz işlemi zaman uyumsuz olarak bekler.

Tanıtım adımlarında, web sitelerinin farklı hızlarda indirildiğini fark etmiş olabilirsiniz. Bazen web sitelerinden biri çok yavaştır ve bu da kalan tüm indirmeleri geciktirmektedir. Adım adım talimatta oluşturduğunuz eşzamansız çözümleri çalıştırdığınızda, beklemek istemiyorsanız programı kolayca sonlandırabilirsiniz; ancak daha iyi bir seçenek, tüm indirmeleri aynı anda başlatmak ve gecikeni beklemeden daha hızlı indirmelerin devam etmesine izin vermektir.

yöntemini bir görev koleksiyonuna uygularsınız Task.WhenAll . uygulaması WhenAll , koleksiyondaki her görev tamamlanana kadar tamamlanmamış tek bir görev döndürür. Görevler paralel olarak çalışıyor gibi görünse de, ek iş parçacığı oluşturulmaz. Görevler herhangi bir sırada tamamlanabilir.

Önemli

Aşağıdaki işlemler, zaman uyumsuz uygulamaların Walkthrough: Async ve Await Kullanarak Web'e Erişme (Visual Basic) kılavuzunda geliştirilen uzantılarını açıklar. İzlenecek yolu tamamlayarak veya örneği .NET Sample Browser'dan indirerek uygulamaları geliştirebilirsiniz. Örnek kod SerialAsyncExample projesindedir.

Örneği çalıştırmak için bilgisayarınızda Visual Studio 2012 veya üzeri yüklü olmalıdır.

GetURLContentsAsync çözümünüze Task.WhenAll eklemek için

  1. ProcessURLAsync yöntemini İzlenecek Yol: Async ve Await (Visual Basic) Kullanarak Web'e Erişme başlığı altında geliştirilen ilk uygulamaya ekleyin.

    • Kodu Geliştirici Kodu Örnekleri'nden indirdiyseniz AsyncWalkthrough projesini açın ve MainWindow.xaml.vb dosyasına ekleyinProcessURLAsync.

    • Kodu adım adım kılavuzu tamamlayarak geliştirdiyseniz, ProcessURLAsync yöntemini içeren uygulamaya GetURLContentsAsync ekleyin. Bu uygulamanın MainWindow.xaml.vb dosyası, "İzlenecek Yol'dan Kod Örneklerini Tamamlama" bölümündeki ilk örnektir.

    ProcessURLAsync yöntemi, For Each döngüsünün gövdesindeki eylemleri SumPageSizesAsync içindeki özgün rehberde birleştirir. yöntemi, belirtilen bir web sitesinin içeriğini zaman uyumsuz olarak bayt dizisi olarak indirir ve bayt dizisinin uzunluğunu görüntüler ve döndürür.

    Private Async Function ProcessURLAsync(url As String) As Task(Of Integer)
    
        Dim byteArray = Await GetURLContentsAsync(url)
        DisplayResults(url, byteArray)
        Return byteArray.Length
    End Function
    
  2. Aşağıdaki kodda gösterildiği gibi içindeki For Eachdöngüye SumPageSizesAsync açıklama ekleyin veya döngünün silinmesini sağlayın.

    'Dim total = 0
    'For Each url In urlList
    
    '    Dim urlContents As Byte() = Await GetURLContentsAsync(url)
    
    '    ' The previous line abbreviates the following two assignment statements.
    
    '    ' GetURLContentsAsync returns a task. At completion, the task
    '    ' produces a byte array.
    '    'Dim getContentsTask As Task(Of Byte()) = GetURLContentsAsync(url)
    '    'Dim urlContents As Byte() = Await getContentsTask
    
    '    DisplayResults(url, urlContents)
    
    '    ' Update the total.
    '    total += urlContents.Length
    'Next
    
  3. Bir görev koleksiyonu oluşturun. Aşağıdaki kod, yöntemi tarafından yürütüldüğünde her web sitesinin içeriğini indiren bir görev koleksiyonu oluşturan bir ToArray tanımlar. Sorgu değerlendirildiğinde görevler başlatılır.

    SumPageSizesAsync bildiriminden sonra urlList yöntemine aşağıdaki kodu ekleyin.

    ' Create a query.
    Dim downloadTasksQuery As IEnumerable(Of Task(Of Integer)) =
        From url In urlList Select ProcessURLAsync(url)
    
    ' Use ToArray to execute the query and start the download tasks.
    Dim downloadTasks As Task(Of Integer)() = downloadTasksQuery.ToArray()
    
  4. Görev koleksiyonuna uygula Task.WhenAll , downloadTasks. Task.WhenAll , görev koleksiyonundaki tüm görevler tamamlandığında biten tek bir görev döndürür.

    Aşağıdaki örnekte, Await döndüren tek görevin tamamlanmasını WhenAll ifadesi bekler. İfade, her tamsayının indirilen bir web sitesinin uzunluğu olduğu bir tamsayı dizisi olarak değerlendirilir. Önceki adımda eklediğiniz kodun SumPageSizesAsynchemen arkasına aşağıdaki kodu ekleyin.

    ' Await the completion of all the running tasks.
    Dim lengths As Integer() = Await Task.WhenAll(downloadTasks)
    
    '' The previous line is equivalent to the following two statements.
    'Dim whenAllTask As Task(Of Integer()) = Task.WhenAll(downloadTasks)
    'Dim lengths As Integer() = Await whenAllTask
    
  5. Son olarak, yöntemini kullanarak Sum tüm web sitelerinin uzunluklarının toplamını hesaplayın. Aşağıdaki satırı SumPageSizesAsync öğesine ekleyin.

    Dim total = lengths.Sum()
    

HttpClient.GetByteArrayAsync çözümüne Task.WhenAll eklemek için

  1. İzlenecek Yol: Async ve Await Kullanarak Web'e Erişme (Visual Basic) içinde geliştirilen ikinci uygulamaya ProcessURLAsync'nin aşağıdaki sürümünü ekleyin.

    • Kodu Geliştirici Kodu Örnekleri'nden indirdiyseniz, AsyncWalkthrough_HttpClient projesini açın ve MainWindow.xaml.vb dosyasına ekleyinProcessURLAsync.

    • Yürütmeliği tamamlayarak kodu geliştirdiyseniz, ProcessURLAsync yöntemini kullanan uygulamaya HttpClient.GetByteArrayAsync ekleyin. Bu uygulamanın MainWindow.xaml.vb dosyası, "İzlenecek Yol'dan Kod Örneklerini Tamamlama" bölümündeki ikinci örnektir.

    ProcessURLAsync yöntemi, For Each döngüsünün gövdesindeki eylemleri SumPageSizesAsync içindeki özgün rehberde birleştirir. yöntemi, belirtilen bir web sitesinin içeriğini zaman uyumsuz olarak bayt dizisi olarak indirir ve bayt dizisinin uzunluğunu görüntüler ve döndürür.

    Önceki yordamdaki ProcessURLAsync yöntemden tek fark, HttpClient kullanılmasıdır client örneğinin.

    Private Async Function ProcessURLAsync(url As String, client As HttpClient) As Task(Of Integer)
    
        Dim byteArray = Await client.GetByteArrayAsync(url)
        DisplayResults(url, byteArray)
        Return byteArray.Length
    End Function
    
  2. Aşağıdaki kodda gösterildiği gibi içindeki For Eachdöngüye SumPageSizesAsync açıklama ekleyin veya döngünün silinmesini sağlayın.

    'Dim total = 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)
    
    '    ' The following two lines can replace the previous assignment statement.
    '    'Dim getContentsTask As Task(Of Byte()) = client.GetByteArrayAsync(url)
    '    'Dim urlContents As Byte() = Await getContentsTask
    
    '    DisplayResults(url, urlContents)
    
    '    ' Update the total.
    '    total += urlContents.Length
    'Next
    
  3. Bir sorgu tanımlayın ki, bu sorgu ToArray yöntemi ile yürütüldüğünde, her web sitesinin içeriğini indiren bir görev koleksiyonu oluştursun. Sorgu değerlendirildiğinde görevler başlatılır.

    Bildirimi yapılan SumPageSizesAsync ve client'den sonra urlList yöntemine aşağıdaki kodu ekleyin.

    ' Create a query.
    Dim downloadTasksQuery As IEnumerable(Of Task(Of Integer)) =
        From url In urlList Select ProcessURLAsync(url, client)
    
    ' Use ToArray to execute the query and start the download tasks.
    Dim downloadTasks As Task(Of Integer)() = downloadTasksQuery.ToArray()
    
  4. Ardından, Task.WhenAll görev koleksiyonuna downloadTasks uygulayın. Task.WhenAll , görev koleksiyonundaki tüm görevler tamamlandığında biten tek bir görev döndürür.

    Aşağıdaki örnekte, Await döndüren tek görevin tamamlanmasını WhenAll ifadesi bekler. tamamlandığında, Await ifade bir tamsayı dizisine göre değerlendirilir; burada her tamsayı indirilen bir web sitesinin uzunluğudur. Önceki adımda eklediğiniz kodun SumPageSizesAsynchemen arkasına aşağıdaki kodu ekleyin.

    ' Await the completion of all the running tasks.
    Dim lengths As Integer() = Await Task.WhenAll(downloadTasks)
    
    '' The previous line is equivalent to the following two statements.
    'Dim whenAllTask As Task(Of Integer()) = Task.WhenAll(downloadTasks)
    'Dim lengths As Integer() = Await whenAllTask
    
  5. Son olarak, tüm web sitelerinin uzunluklarının toplamını almak için yöntemini kullanın Sum . Aşağıdaki satırı SumPageSizesAsync öğesine ekleyin.

    Dim total = lengths.Sum()
    

Task.WhenAll çözümlerini test etmek için

Her iki çözüm için de programı çalıştırmak için F5 tuşunu seçin ve ardından Başlat düğmesini seçin. Çıkış, İzlenecek Yol: Async ve Await Kullanarak Web'e Erişme (Visual Basic) içindeki zaman uyumsuz çözümlerden elde edilen çıkışa benzemelidir. Ancak, web sitelerinin her seferinde farklı bir sırada göründüğüne dikkat edin.

Örnek 1

Aşağıdaki kod, web'den içerik indirmek için yöntemini kullanan GetURLContentsAsync projenin uzantılarını gösterir.

' Add the following Imports statements, and add a reference for System.Net.Http.
Imports System.Net.Http
Imports System.Net
Imports System.IO

Class MainWindow

    Async Sub startButton_Click(sender As Object, e As RoutedEventArgs) Handles startButton.Click

        resultsTextBox.Clear()

        ' One-step async call.
        Await SumPageSizesAsync()

        '' Two-step async call.
        'Dim sumTask As Task = SumPageSizesAsync()
        'Await sumTask

        resultsTextBox.Text &= vbCrLf & "Control returned to button1_Click."
    End Sub

    Private Async Function SumPageSizesAsync() As Task

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

        ' Create a query.
        Dim downloadTasksQuery As IEnumerable(Of Task(Of Integer)) =
            From url In urlList Select ProcessURLAsync(url)

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

        ' You can do other work here before awaiting.

        ' Await the completion of all the running tasks.
        Dim lengths As Integer() = Await Task.WhenAll(downloadTasks)

        '' The previous line is equivalent to the following two statements.
        'Dim whenAllTask As Task(Of Integer()) = Task.WhenAll(downloadTasks)
        'Dim lengths As Integer() = Await whenAllTask

        Dim total = lengths.Sum()

        'Dim total = 0
        'For Each url In urlList

        '    Dim urlContents As Byte() = Await GetURLContentsAsync(url)

        '    ' The previous line abbreviates the following two assignment statements.

        '    ' GetURLContentsAsync returns a task. At completion, the task
        '    ' produces a byte array.
        '    'Dim getContentsTask As Task(Of Byte()) = GetURLContentsAsync(url)
        '    'Dim urlContents As Byte() = Await getContentsTask

        '    DisplayResults(url, urlContents)

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

        ' Display the total count for all of the web addresses.
        resultsTextBox.Text &= String.Format(vbCrLf & vbCrLf &
                                             "Total bytes returned:  {0}" & vbCrLf, total)
    End Function

    Private Function SetUpURLList() As List(Of String)

        Dim urls = New List(Of String) From
            {
                "https://msdn.microsoft.com",
                "https://msdn.microsoft.com/library/hh290136.aspx",
                "https://msdn.microsoft.com/library/ee256749.aspx",
                "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

    ' The actions from the foreach loop are moved to this async method.
    Private Async Function ProcessURLAsync(url As String) As Task(Of Integer)

        Dim byteArray = Await GetURLContentsAsync(url)
        DisplayResults(url, byteArray)
        Return byteArray.Length
    End Function

    Private Async Function GetURLContentsAsync(url As String) As Task(Of Byte())

        ' The downloaded resource ends up in the variable named content.
        Dim content = New MemoryStream()

        ' Initialize an HttpWebRequest for the current URL.
        Dim webReq = CType(WebRequest.Create(url), HttpWebRequest)

        ' Send the request to the Internet resource and wait for
        ' the response.
        Using response As WebResponse = Await webReq.GetResponseAsync()
            ' Get the data stream that is associated with the specified URL.
            Using responseStream As Stream = response.GetResponseStream()
                ' Read the bytes in responseStream and copy them to content.
                ' CopyToAsync returns a Task, not a Task<T>.
                Await responseStream.CopyToAsync(content)
            End Using
        End Using

        ' Return the result as a byte array.
        Return content.ToArray()
    End Function

    Private Sub DisplayResults(url As String, content As Byte())

        ' 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.
        Dim bytes = content.Length
        ' Strip off the "https://".
        Dim displayURL = url.Replace("https://", "")
        resultsTextBox.Text &= String.Format(vbCrLf & "{0,-58} {1,8}", displayURL, bytes)
    End Sub

End Class

Örnek 2

Aşağıdaki kod, web'den içerik indirmek için yöntemini HttpClient.GetByteArrayAsync kullanan projenin uzantılarını gösterir.

' Add the following Imports statements, and add a reference for System.Net.Http.
Imports System.Net.Http
Imports System.Net
Imports System.IO

Class MainWindow

    Async Sub startButton_Click(sender As Object, e As RoutedEventArgs) Handles startButton.Click

        resultsTextBox.Clear()

        '' One-step async call.
        Await SumPageSizesAsync()

        '' Two-step async call.
        'Dim sumTask As Task = SumPageSizesAsync()
        'Await sumTask

        resultsTextBox.Text &= vbCrLf & "Control returned to button1_Click."
    End Sub

    Private Async Function SumPageSizesAsync() As Task

        ' Declare an HttpClient object and increase the buffer size. The
        ' default buffer size is 65,536.
        Dim client As HttpClient =
            New HttpClient() With {.MaxResponseContentBufferSize = 1000000}

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

        ' Create a query.
        Dim downloadTasksQuery As IEnumerable(Of Task(Of Integer)) =
            From url In urlList Select ProcessURLAsync(url, client)

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

        ' You can do other work here before awaiting.

        ' Await the completion of all the running tasks.
        Dim lengths As Integer() = Await Task.WhenAll(downloadTasks)

        '' The previous line is equivalent to the following two statements.
        'Dim whenAllTask As Task(Of Integer()) = Task.WhenAll(downloadTasks)
        'Dim lengths As Integer() = Await whenAllTask

        Dim total = lengths.Sum()

        ''<snippet7>
        'Dim total = 0
        'For Each url In urlList
        '    ' GetByteArrayAsync returns a task. At completion, the task
        '    ' produces a byte array.
        '    '<snippet31>
        '    Dim urlContents As Byte() = Await client.GetByteArrayAsync(url)
        '    '</snippet31>

        '    ' The following two lines can replace the previous assignment statement.
        '    'Dim getContentsTask As Task(Of Byte()) = client.GetByteArrayAsync(url)
        '    'Dim urlContents As Byte() = Await getContentsTask

        '    DisplayResults(url, urlContents)

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

        ' Display the total count for all of the web addresses.
        resultsTextBox.Text &= String.Format(vbCrLf & vbCrLf &
                                             "Total bytes returned:  {0}" & vbCrLf, total)
    End Function

    Private Function SetUpURLList() As List(Of String)

        Dim urls = New List(Of String) From
            {
                "https://www.msdn.com",
                "https://msdn.microsoft.com/library/hh290136.aspx",
                "https://msdn.microsoft.com/library/ee256749.aspx",
                "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

    Private Async Function ProcessURLAsync(url As String, client As HttpClient) As Task(Of Integer)

        Dim byteArray = Await client.GetByteArrayAsync(url)
        DisplayResults(url, byteArray)
        Return byteArray.Length
    End Function

    Private Sub DisplayResults(url As String, content As Byte())

        ' 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.
        Dim bytes = content.Length
        ' Strip off the "https://".
        Dim displayURL = url.Replace("https://", "")
        resultsTextBox.Text &= String.Format(vbCrLf & "{0,-58} {1,8}", displayURL, bytes)
    End Sub

End Class

Ayrıca bakınız