How to: Make Multiple Web Requests in Parallel by Using Async and Await (Visual Basic) (Практическое руководство. Параллельное выполнение нескольких веб-запросов с использованием Async и Await (Visual Basic))

В асинхронном методе задачи запускаются в момент создания. Оператор Await применяется к задаче в точке метода, где обработка не может продолжаться до завершения задачи. Часто задачи ожидаются в момент создания, как показано в следующем примере.

Dim result = Await someWebAccessMethodAsync(url)

Тем не менее можно отделить создание задачи от ее ожидания, если программа содержит другую работу, выполнение которой не зависит от завершения задачи.

' The following line creates and starts the task.
Dim myTask = someWebAccessMethodAsync(url)

' While the task is running, you can do other work that does not depend
' on the results of the task.
' . . . . .

' The application of Await suspends the rest of this method until the task is
' complete.
Dim result = Await myTask

Между моментом запуска задачи и ее ожиданием можно запустить другие задачи. Дополнительные задачи неявно выполняются параллельно, однако дополнительные потоки не создаются.

Следующая программа запускает три асинхронные веб-загрузки, а затем ожидает их в том порядке, в котором они вызываются. Обратите внимание, что при запуске программы задачи не всегда завершаются в том порядке, в котором они созданы и ожидаются. Они начинают выполняться в момент создания, и одна или несколько задач могут завершиться прежде, чем метод достигает выражения await.

Примечание.

Для выполнения этого проекта необходимо, чтобы на компьютере были установлены Visual Studio 2012 или более поздняя версия и .NET Framework 4.5 или более поздняя версия.

Другой пример, который запускает несколько задач одновременно, см. в разделе "Практическое руководство. Расширение асинхронного пошагового руководства с помощью task.WhenAll (Visual Basic)".

Код для этого примера можно скачать на странице Примеры кода от разработчиков.

Настройка проекта

  1. Чтобы настроить приложение WPF, выполните следующие действия. Подробные инструкции см. в пошаговом руководстве. Доступ к Интернету с помощью Async и Await (Visual Basic).

    • Создайте приложение WPF, которое содержит текстовое поле и кнопку. Назовите кнопку startButton, а текстовое поле — resultsTextBox.

    • Добавьте ссылку для System.Net.Http.

    • В файле MainWindow.xaml.vb добавьте инструкцию Imports для System.Net.Http.

Добавление кода

  1. В окне конструктора MainWindow.xaml дважды щелкните кнопку, чтобы создать startButton_Click обработчик событий в MainWindow.xaml.vb.

  2. Скопируйте следующий код и вставьте его в текст startButton_Click MainWindow.xaml.vb.

    resultsTextBox.Clear()
    Await CreateMultipleTasksAsync()
    resultsTextBox.Text &= vbCrLf & "Control returned to button1_Click."
    

    Код вызывает асинхронный метод CreateMultipleTasksAsync, который управляет приложением.

  3. Добавьте следующие вспомогательные методы в проект:

    • ProcessURLAsync использует метод HttpClient для скачивания содержимого веб-сайта в виде массива байтов. Вспомогательный метод ProcessURLAsync затем отображает и возвращает длину массива.

    • DisplayResults показывает число байтов в массиве байтов для каждого URL-адреса. Эти выходные данные показывают, когда именно каждая задача завершает загрузку.

    Скопируйте следующие методы и вставьте их после обработчика startButton_Click событий в MainWindow.xaml.vb.

    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
    
  4. Наконец, определите метод CreateMultipleTasksAsync, который выполняет следующие действия.

    • Этот метод объявляет объект HttpClient, который используется методом доступа GetByteArrayAsync в ProcessURLAsync.

    • Метод создает и запускает три задачи типа Task<TResult>, где TResult является целым числом. При завершении каждой задачи DisplayResults отображает URL-адрес и длину загруженного содержимого задачи. Поскольку задачи выполняются асинхронно, порядок, в котором отображаются результаты, может отличаться от порядка, в котором они были объявлены.

    • Метод ожидает завершения каждой задачи. Каждый оператор Await приостанавливает выполнение CreateMultipleTasksAsync до завершения выполнения ожидаемой задачи. Оператор также получает возвращаемое значение вызова ProcessURLAsync от каждой завершенной задачи.

    • После завершения задач и получения целочисленных значений метод суммирует длину веб-сайтов и отображает результат.

    Скопируйте следующий метод и вставьте его в решение.

    Private Async Function CreateMultipleTasksAsync() 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}
    
        ' Create and start the tasks. As each task finishes, DisplayResults
        ' displays its length.
        Dim download1 As Task(Of Integer) =
            ProcessURLAsync("https://msdn.microsoft.com", client)
        Dim download2 As Task(Of Integer) =
            ProcessURLAsync("https://msdn.microsoft.com/library/hh156528(VS.110).aspx", client)
        Dim download3 As Task(Of Integer) =
            ProcessURLAsync("https://msdn.microsoft.com/library/67w7t67f.aspx", client)
    
        ' Await each task.
        Dim length1 As Integer = Await download1
        Dim length2 As Integer = Await download2
        Dim length3 As Integer = Await download3
    
        Dim total As Integer = length1 + length2 + length3
    
        ' Display the total count for all of the websites.
        resultsTextBox.Text &= String.Format(vbCrLf & vbCrLf &
                                             "Total bytes returned:  {0}" & vbCrLf, total)
    End Function
    
  5. Нажмите клавишу F5, чтобы запустить программу, а затем нажмите кнопку Start .

    Запустите программу несколько раз, чтобы убедиться, что три задачи не всегда завершаются в том же порядке, а порядок их завершения не обязательно совпадает с порядком, в котором они создаются и ожидаются.

Пример

Следующий код содержит полный пример.

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

Class MainWindow

    Async Sub startButton_Click(sender As Object, e As RoutedEventArgs) Handles startButton.Click
        resultsTextBox.Clear()
        Await CreateMultipleTasksAsync()
        resultsTextBox.Text &= vbCrLf & "Control returned to button1_Click."
    End Sub

    Private Async Function CreateMultipleTasksAsync() 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}

        ' Create and start the tasks. As each task finishes, DisplayResults
        ' displays its length.
        Dim download1 As Task(Of Integer) =
            ProcessURLAsync("https://msdn.microsoft.com", client)
        Dim download2 As Task(Of Integer) =
            ProcessURLAsync("https://msdn.microsoft.com/library/hh156528(VS.110).aspx", client)
        Dim download3 As Task(Of Integer) =
            ProcessURLAsync("https://msdn.microsoft.com/library/67w7t67f.aspx", client)

        ' Await each task.
        Dim length1 As Integer = Await download1
        Dim length2 As Integer = Await download2
        Dim length3 As Integer = Await download3

        Dim total As Integer = length1 + length2 + length3

        ' Display the total count for all of the websites.
        resultsTextBox.Text &= String.Format(vbCrLf & vbCrLf &
                                             "Total bytes returned:  {0}" & vbCrLf, total)
    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

См. также