How to: Make Multiple Web Requests in Parallel by Using Async and Await (Visual Basic)
In an async method, tasks are started when they’re created. The Await operator is applied to the task at the point in the method where processing can’t continue until the task finishes. Often a task is awaited as soon as it’s created, as the following example shows.
Dim result = Await someWebAccessMethodAsync(url)
However, you can separate creating the task from awaiting the task if your program has other work to accomplish that doesn’t depend on the completion of the task.
' 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
Between starting a task and awaiting it, you can start other tasks. The additional tasks implicitly run in parallel, but no additional threads are created.
The following program starts three asynchronous web downloads and then awaits them in the order in which they’re called. Notice, when you run the program, that the tasks don’t always finish in the order in which they’re created and awaited. They start to run when they’re created, and one or more of the tasks might finish before the method reaches the await expressions.
Note
To complete this project, you must have Visual Studio 2012 or higher and the .NET Framework 4.5 or higher installed on your computer.
For another example that starts multiple tasks at the same time, see How to: Extend the Async Walkthrough by Using Task.WhenAll (Visual Basic).
You can download the code for this example from Developer Code Samples.
To set up the project
To set up a WPF application, complete the following steps. You can find detailed instructions for these steps in Walkthrough: Accessing the Web by Using Async and Await (Visual Basic).
Create a WPF application that contains a text box and a button. Name the button
startButton
, and name the text boxresultsTextBox
.Add a reference for System.Net.Http.
In the MainWindow.xaml.vb file, add an
Imports
statement forSystem.Net.Http
.
To add the code
In the design window, MainWindow.xaml, double-click the button to create the
startButton_Click
event handler in MainWindow.xaml.vb.Copy the following code, and paste it into the body of
startButton_Click
in MainWindow.xaml.vb.resultsTextBox.Clear() Await CreateMultipleTasksAsync() resultsTextBox.Text &= vbCrLf & "Control returned to button1_Click."
The code calls an asynchronous method,
CreateMultipleTasksAsync
, which drives the application.Add the following support methods to the project:
ProcessURLAsync
uses an HttpClient method to download the contents of a website as a byte array. The support method,ProcessURLAsync
then displays and returns the length of the array.DisplayResults
displays the number of bytes in the byte array for each URL. This display shows when each task has finished downloading.
Copy the following methods, and paste them after the
startButton_Click
event handler in 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
Finally, define method
CreateMultipleTasksAsync
, which performs the following steps.The method declares an
HttpClient
object,which you need to access method GetByteArrayAsync inProcessURLAsync
.The method creates and starts three tasks of type Task<TResult>, where
TResult
is an integer. As each task finishes,DisplayResults
displays the task's URL and the length of the downloaded contents. Because the tasks are running asynchronously, the order in which the results appear might differ from the order in which they were declared.The method awaits the completion of each task. Each
Await
operator suspends execution ofCreateMultipleTasksAsync
until the awaited task is finished. The operator also retrieves the return value from the call toProcessURLAsync
from each completed task.When the tasks have been completed and the integer values have been retrieved, the method sums the lengths of the websites and displays the result.
Copy the following method, and paste it into your solution.
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
Choose the F5 key to run the program, and then choose the Start button.
Run the program several times to verify that the three tasks don’t always finish in the same order and that the order in which they finish isn't necessarily the order in which they’re created and awaited.
Example
The following code contains the full example.
' 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