Gör så här: Utöka Async-genomgången med hjälp av aktivitet.WhenAll (Visual Basic)
Du kan förbättra prestanda för asynkron lösning i Genomgång: Åtkomst till webben med hjälp av Async och Await (Visual Basic) med hjälp Task.WhenAll av metoden. Den här metoden väntar asynkront på flera asynkrona åtgärder, som representeras som en samling uppgifter.
Du kanske har märkt i genomgången att webbplatserna laddas ned till olika priser. Ibland är en av webbplatserna mycket långsam, vilket fördröjer alla återstående nedladdningar. När du kör de asynkrona lösningar som du skapar i genomgången kan du enkelt avsluta programmet om du inte vill vänta, men ett bättre alternativ är att starta alla nedladdningar samtidigt och låta snabbare nedladdningar fortsätta utan att vänta på den som är försenad.
Du använder metoden för Task.WhenAll
en samling uppgifter. Programmet WhenAll
returnerar en enskild uppgift som inte har slutförts förrän varje uppgift i samlingen har slutförts. Uppgifterna verkar köras parallellt, men inga ytterligare trådar skapas. Uppgifterna kan slutföras i valfri ordning.
Viktigt!
Följande procedurer beskriver tillägg till de asynkrona program som har utvecklats i Genomgång: Åtkomst till webben med hjälp av Async och Await (Visual Basic). Du kan utveckla programmen genom att antingen slutföra genomgången eller ladda ned exemplet från .NET Sample Browser. Exempelkoden finns i SerialAsyncExample-projektet .
Om du vill köra exemplet måste du ha Visual Studio 2012 eller senare installerat på datorn.
Så här lägger du till Task.WhenAll i din GetURLContentsAsync-lösning
ProcessURLAsync
Lägg till metoden i det första programmet som har utvecklats i Genomgång: Åtkomst till webben med hjälp av Async och Await (Visual Basic).Om du har laddat ned koden från Developer Code Samples öppnar du projektet AsyncWalkthrough och lägger sedan till
ProcessURLAsync
den MainWindow.xaml.vb filen.Om du har utvecklat koden genom att slutföra genomgången lägger du till
ProcessURLAsync
i programmet som innehållerGetURLContentsAsync
-metoden. Den MainWindow.xaml.vb filen för det här programmet är det första exemplet i avsnittet "Slutför kodexempel från genomgången".
Metoden
ProcessURLAsync
konsoliderar åtgärderna i loopensFor Each
brödtext iSumPageSizesAsync
den ursprungliga genomgången. Metoden laddar asynkront ned innehållet på en angiven webbplats som en bytematris och visar och returnerar sedan längden på bytematrisen.Private Async Function ProcessURLAsync(url As String) As Task(Of Integer) Dim byteArray = Await GetURLContentsAsync(url) DisplayResults(url, byteArray) Return byteArray.Length End Function
Kommentera ut eller ta bort loopen
For Each
iSumPageSizesAsync
, som följande kod visar.'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
Skapa en samling uppgifter. Följande kod definierar en fråga som när den ToArray körs med metoden skapar en samling uppgifter som laddar ned innehållet på varje webbplats. Uppgifterna startas när frågan utvärderas.
Lägg till följande kod i metoden
SumPageSizesAsync
efter deklarationen avurlList
.' 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()
Använd
Task.WhenAll
för samlingen med uppgifter,downloadTasks
.Task.WhenAll
returnerar en enskild uppgift som avslutas när alla aktiviteter i samlingen med uppgifter har slutförts.I följande exempel
Await
väntar uttrycket på slutförandet av den enda uppgift somWhenAll
returneras. Uttrycket utvärderas till en matris med heltal, där varje heltal är längden på en nedladdad webbplats. Lägg till följande kod iSumPageSizesAsync
, strax efter den kod som du lade till i föregående steg.' 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
Slutligen använder du Sum metoden för att beräkna summan av längden på alla webbplatser. Lägg till följande rad i
SumPageSizesAsync
.Dim total = lengths.Sum()
Så här lägger du till Task.WhenAll i lösningen HttpClient.GetByteArrayAsync
Lägg till följande version av
ProcessURLAsync
i det andra programmet som har utvecklats i Genomgång: Åtkomst till webben med hjälp av Async och Await (Visual Basic).Om du har hämtat koden från Developer Code Samples öppnar du projektet AsyncWalkthrough_HttpClient och lägger sedan till
ProcessURLAsync
den MainWindow.xaml.vb filen.Om du har utvecklat koden genom att slutföra genomgången lägger du till
ProcessURLAsync
i programmet som använderHttpClient.GetByteArrayAsync
-metoden. Den MainWindow.xaml.vb filen för det här programmet är det andra exemplet i avsnittet "Slutför kodexempel från genomgången".
Metoden
ProcessURLAsync
konsoliderar åtgärderna i loopensFor Each
brödtext iSumPageSizesAsync
den ursprungliga genomgången. Metoden laddar asynkront ned innehållet på en angiven webbplats som en bytematris och visar och returnerar sedan längden på bytematrisen.Den enda skillnaden från
ProcessURLAsync
metoden i föregående procedur är användningen av instansen HttpClient ,client
.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
Kommentera ut eller ta bort loopen
For Each
iSumPageSizesAsync
, som följande kod visar.'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
Definiera en fråga som när den ToArray körs med metoden skapar en samling uppgifter som laddar ned innehållet på varje webbplats. Uppgifterna startas när frågan utvärderas.
Lägg till följande kod i metoden
SumPageSizesAsync
efter deklarationen avclient
ochurlList
.' 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()
Tillämpa
Task.WhenAll
sedan på samlingen med uppgifter,downloadTasks
.Task.WhenAll
returnerar en enskild uppgift som avslutas när alla aktiviteter i samlingen med uppgifter har slutförts.I följande exempel
Await
väntar uttrycket på slutförandet av den enda uppgift somWhenAll
returneras. När detAwait
är klart utvärderas uttrycket till en matris med heltal, där varje heltal är längden på en nedladdad webbplats. Lägg till följande kod iSumPageSizesAsync
, strax efter den kod som du lade till i föregående steg.' 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
Slutligen använder du Sum metoden för att få summan av längden på alla webbplatser. Lägg till följande rad i
SumPageSizesAsync
.Dim total = lengths.Sum()
Testa Task.WhenAll-lösningar
För någon av lösningarna väljer du F5-nyckeln för att köra programmet och väljer sedan knappen Start . Utdata bör likna utdata från asynkrona lösningar i Genomgång: Åtkomst till webben med hjälp av Async och Await (Visual Basic). Observera dock att webbplatserna visas i en annan ordning varje gång.
Exempel 1
Följande kod visar tilläggen till projektet som använder GetURLContentsAsync
metoden för att ladda ned innehåll från webben.
' 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
Exempel 2
Följande kod visar tilläggen till projektet som använder metoden HttpClient.GetByteArrayAsync
för att ladda ned innehåll från webben.
' 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