非同期ソリューションのパフォーマンスを向上させるには、「 チュートリアル: Async と Await を使用した Web へのアクセス (Visual Basic) 、 Task.WhenAll メソッドを使用する」を参照してください。 このメソッドは、タスクのコレクションとして表される複数の非同期操作を非同期的に待機します。
このチュートリアルでは、Web サイトが異なる料金でダウンロードされていることに気付いたかもしれません。 場合によっては、Web サイトの 1 つが非常に遅く、残りのすべてのダウンロードが遅くなることがあります。 チュートリアルでビルドした非同期ソリューションを実行すると、待機したくない場合はプログラムを簡単に終了できますが、すべてのダウンロードを同時に開始し、遅延したダウンロードを待たずに高速ダウンロードを続行することをお勧めします。
Task.WhenAll
メソッドは、タスクのコレクションに適用します。
WhenAll
のアプリケーションは、コレクション内のすべてのタスクが完了するまで完了しない 1 つのタスクを返します。 タスクは並列で実行されているように見えますが、追加のスレッドは作成されません。 タスクは任意の順序で完了できます。
Von Bedeutung
次の手順では、「 チュートリアル: Async と Await を使用した Web へのアクセス (Visual Basic)」で開発された非同期アプリケーションの拡張機能について説明します。 アプリケーションを開発するには、チュートリアルを完了するか、.NET サンプル ブラウザーからサンプルをダウンロードします。 サンプル コードは SerialAsyncExample プロジェクト内にあります。
この例を実行するには、Visual Studio 2012 以降がコンピューターにインストールされている必要があります。
GetURLContentsAsync ソリューションに Task.WhenAll を追加するには
「チュートリアル: Async と Await を使用した Web へのアクセス (Visual Basic)」で開発した最初のアプリケーションに、
ProcessURLAsync
メソッドを追加します。開発者コード サンプルからコードをダウンロードした場合は、AsyncWalkthrough プロジェクトを開き、MainWindow.xaml.vb ファイルに
ProcessURLAsync
を追加します。チュートリアルを完了してコードを開発した場合は、
GetURLContentsAsync
メソッドを含むProcessURLAsync
をアプリケーションに追加します。 このアプリケーションのMainWindow.xaml.vb ファイルは、「チュートリアルの完全なコード例」セクションの最初の例です。
ProcessURLAsync
メソッドは、元のチュートリアルのSumPageSizesAsync
のFor Each
ループの本文のアクションを統合します。 メソッドは、指定した Web サイトの内容をバイト配列として非同期的にダウンロードし、バイト配列の長さを表示して返します。Private Async Function ProcessURLAsync(url As String) As Task(Of Integer) Dim byteArray = Await GetURLContentsAsync(url) DisplayResults(url, byteArray) Return byteArray.Length End Function
次のコードに示すように、
SumPageSizesAsync
のFor Each
ループをコメント アウトまたは削除します。'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
タスクのコレクションを作成します。 次のコードは、ToArray メソッドによって実行されたときに、各 Web サイトの内容をダウンロードするタスクのコレクションを作成するクエリを定義します。 タスクは、クエリの評価時に開始されます。
urlList
の宣言の後に、メソッドSumPageSizesAsync
に次のコードを追加します。' 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()
タスクのコレクション (
downloadTasks
) にTask.WhenAll
を適用します。Task.WhenAll
は、タスクのコレクション内のすべてのタスクが完了したときに完了する 1 つのタスクを返します。次の例では、
Await
式は、WhenAll
が返す 1 つのタスクの完了を待機しています。 式は整数の配列に評価されます。各整数は、ダウンロードした Web サイトの長さです。 前の手順で追加したコードの直後に、次のコードをSumPageSizesAsync
に追加します。' 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
最後に、 Sum メソッドを使用して、すべての Web サイトの長さの合計を計算します。 次の行を
SumPageSizesAsync
に追加します。Dim total = lengths.Sum()
Task.WhenAll を HttpClient.GetByteArrayAsync ソリューションに追加するには
「チュートリアル: Async と Await を使用した Web へのアクセス (Visual Basic)」で開発した 2 番目のアプリケーションに、次のバージョンの
ProcessURLAsync
を追加します。開発者コード サンプルからコードをダウンロードした場合は、AsyncWalkthrough_HttpClient プロジェクトを開き、MainWindow.xaml.vb ファイルに
ProcessURLAsync
を追加します。チュートリアルを完了してコードを開発した場合は、
HttpClient.GetByteArrayAsync
メソッドを使用するアプリケーションにProcessURLAsync
を追加します。 このアプリケーションのMainWindow.xaml.vb ファイルは、「チュートリアルの完全なコード例」セクションの 2 番目の例です。
ProcessURLAsync
メソッドは、元のチュートリアルのSumPageSizesAsync
のFor Each
ループの本文のアクションを統合します。 メソッドは、指定した Web サイトの内容をバイト配列として非同期的にダウンロードし、バイト配列の長さを表示して返します。前の手順の
ProcessURLAsync
メソッドとの唯一の違いは、 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
次のコードに示すように、
SumPageSizesAsync
のFor Each
ループをコメント アウトまたは削除します。'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
ToArray メソッドによって実行されたときに、各 Web サイトのコンテンツをダウンロードするタスクのコレクションを作成するクエリを定義します。 タスクは、クエリの評価時に開始されます。
client
とurlList
の宣言の後に、メソッドSumPageSizesAsync
に次のコードを追加します。' 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()
次に、タスクのコレクション (
downloadTasks
) にTask.WhenAll
を適用します。Task.WhenAll
は、タスクのコレクション内のすべてのタスクが完了したときに完了する 1 つのタスクを返します。次の例では、
Await
式は、WhenAll
が返す 1 つのタスクの完了を待機しています。 完了すると、Await
式は整数の配列に評価されます。各整数は、ダウンロードした Web サイトの長さです。 前の手順で追加したコードの直後に、次のコードをSumPageSizesAsync
に追加します。' 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
最後に、 Sum メソッドを使用して、すべての Web サイトの長さの合計を取得します。 次の行を
SumPageSizesAsync
に追加します。Dim total = lengths.Sum()
Task.WhenAll ソリューションをテストするには
どちらのソリューションでも、F5 キーを押してプログラムを実行し、[ スタート ] ボタンを選択します。 出力は、「 チュートリアル: Async と Await を使用した Web へのアクセス (Visual Basic)」の非同期ソリューションからの出力のようになります。 ただし、Web サイトは毎回異なる順序で表示されます。
例 1
次のコードは、 GetURLContentsAsync
メソッドを使用して Web からコンテンツをダウンロードするプロジェクトの拡張機能を示しています。
' 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
例 2
次のコードは、メソッド HttpClient.GetByteArrayAsync
を使用して Web からコンテンツをダウンロードするプロジェクトの拡張機能を示しています。
' 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
こちらも参照ください
.NET