方法: Async と Await を使用して複数の Web 要求を並列実行する (C# および Visual Basic)
非同期メソッドでは、タスクは作成されると開始されます。 Await (Visual Basic) または await (C#) 演算子はメソッド内でタスクが終了するまで処理が続行できない時点で、タスクに適用されます。 次の例に示すように、タスクは多くの場合、作成されるとすぐに待機します。
Dim result = Await someWebAccessMethodAsync(url)
var 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
// The following line creates and starts the task.
var myTask = someWebAccessMethodAsync(url);
// While the task is running, you can do other work that doesn't depend
// on the results of the task.
// . . . . .
// The application of await suspends the rest of this method until the task is complete.
var result = await myTask;
タスクを開始して待機する間に、他のタスクを開始できます。 追加のタスクは暗黙的に並列で実行されますが、追加のスレッドは作成されません。
次のプログラムは 3 つの非同期的な Web ダウンロードを開始し、次に呼び出した順にそれを待機します。 プログラムを実行する場合、タスクは必ずしも作成して待機した順には終了しないことに注意します。 タスクは作成されると実行され、メソッドが await 式に到達する前に 1 つまたは複数のタスクが終了する場合もあります。
注意
このプロジェクトを完成させるには、Visual Studio 2012、Visual Studio 2013、Visual Studio Express 2012 for Windows Desktop、Visual Studio Express 2013 for Windows、または .NET Framework 4.5 か 4.5.1 がコンピューターにインストールされている必要があります。
複数のタスクを同時に開始する別の例については、「方法: Task.WhenAll を使用して AsyncWalkthrough を拡張する (C# および Visual Basic)」を参照してください。
この例のコードは、開発者コード サンプル のページからダウンロードできます。
プロジェクトを設定するには
WPF アプリケーションを設定するには、次の手順を実行します。 これらの手順の詳細については、「チュートリアル: Async と Await を使用した Web へのアクセス (C# および Visual Basic)」を参照してください。
テキスト ボックスとボタンを含む WPF アプリケーションを作成します。 ボタンに startButton という名前を付け、テキスト ボックスに resultsTextBox という名前を付けます。
System.Net.Http への参照を追加します。
MainWindow.xaml.vb または MainWindow.xaml.cs で、System.Net.Http に Imports ステートメントまたは using ディレクティブを追加します。
コードを追加するには
デザイン ウィンドウの MainWindow.xaml で、ボタンをダブルクリックして、MainWindow.xaml.vb または MainWindow.xaml.cs に startButton_Click イベント ハンドラーを作成します。 または、ボタンをクリックし、[プロパティ] ウィンドウの [選択された要素のイベント ハンドラー] アイコンをクリックし、次に [クリック] テキスト ボックスで「startButton_Click」と入力します。
次のコードをコピーし、それを MainWindow.xaml.vb または MainWindow.xaml.cs の startButton_Click の本体に貼り付けます。
resultsTextBox.Clear() Await CreateMultipleTasksAsync() resultsTextBox.Text &= vbCrLf & "Control returned to button1_Click."
resultsTextBox.Clear(); await CreateMultipleTasksAsync(); resultsTextBox.Text += "\r\n\r\nControl returned to startButton_Click.\r\n";
このコードは、アプリケーションを呼び出す非同期メソッドである CreateMultipleTasksAsync を呼び出します。
プロジェクトに次のサポート メソッドを追加します。
ProcessURLAsync は HttpClient メソッドを使用して、Web サイトのコンテンツをバイト配列としてダウンロードします。 次に ProcessURLAsync サポート メソッドは、配列の長さを表示して返します。
DisplayResults は各 URL のバイト配列内のバイトの数を表示します。 この表示は、各タスクがいつダウンロードを完了したかを示します。
次のメソッドをコピーし、それを MainWindow.xaml.vb または MainWindow.xaml.cs の startButton_Click の後に貼り付けます。
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 "http://". Dim displayURL = url.Replace("http://", "") resultsTextBox.Text &= String.Format(vbCrLf & "{0,-58} {1,8}", displayURL, bytes) End Sub
async Task<int> ProcessURLAsync(string url, HttpClient client) { var byteArray = await client.GetByteArrayAsync(url); DisplayResults(url, byteArray); return byteArray.Length; } private void DisplayResults(string url, byte[] content) { // 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. var bytes = content.Length; // Strip off the "http://". var displayURL = url.Replace("http://", ""); resultsTextBox.Text += string.Format("\n{0,-58} {1,8}", displayURL, bytes); }
最後に、次の手順を実行するメソッド CreateMultipleTasksAsync を定義します。
このメソッドは、ProcessURLAsync の GetByteArrayAsync メソッドにアクセスするために必要な HttpClient オブジェクトを宣言します。
このメソッドは TResult が整数である Task 型の 3 つのタスクを作成して開始します。 各タスクが終了すると、DisplayResults はタスクの URL とダウンロードしたコンテンツの長さを表示します。 タスクは非同期的に実行されるため、結果が表示される順序は、宣言された順序と異なる場合があります。
メソッドは、各タスクの完了を待機します。 Await または await の各演算子は、待機したタスクが終了するまで CreateMultipleTasksAsync の実行を中断します。 さらに演算子は、完了した各タスクから ProcessURLAsync への呼び出しからの戻り値を取得します。
タスクが完了して整数値が取得されると、メソッドは Web サイトの長さの合計し、その結果を表示します。
次のメソッドをコピーしてソリューションに貼り付けます。
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/en-us/library/hh156528(VS.110).aspx", client) Dim download3 As Task(Of Integer) = ProcessURLAsync("https://msdn.microsoft.com/en-us/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 Task CreateMultipleTasksAsync() { // Declare an HttpClient object, and increase the buffer size. The // default buffer size is 65,536. HttpClient client = new HttpClient() { MaxResponseContentBufferSize = 1000000 }; // Create and start the tasks. As each task finishes, DisplayResults // displays its length. Task<int> download1 = ProcessURLAsync("https://msdn.microsoft.com", client); Task<int> download2 = ProcessURLAsync("https://msdn.microsoft.com/en-us/library/hh156528(VS.110).aspx", client); Task<int> download3 = ProcessURLAsync("https://msdn.microsoft.com/en-us/library/67w7t67f.aspx", client); // Await each task. int length1 = await download1; int length2 = await download2; int length3 = await download3; int total = length1 + length2 + length3; // Display the total count for the downloaded websites. resultsTextBox.Text += string.Format("\r\n\r\nTotal bytes returned: {0}\r\n", total); }
F5 キーを押してプログラムを実行し、[Start] を複数回クリックします。
プログラムを複数回実行して、3 つのタスクが必ずしも同じ順序では完了しないこと、また完了の順序は必ずしも作成され待機した順序と同じではないことを確認します。
使用例
ここまでの例をすべて含んだコードを次に示します。
' 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/en-us/library/hh156528(VS.110).aspx", client)
Dim download3 As Task(Of Integer) =
ProcessURLAsync("https://msdn.microsoft.com/en-us/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 "http://".
Dim displayURL = url.Replace("http://", "")
resultsTextBox.Text &= String.Format(vbCrLf & "{0,-58} {1,8}", displayURL, bytes)
End Sub
End Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
// Add the following using directive, and add a reference for System.Net.Http.
using System.Net.Http;
namespace AsyncExample_MultipleTasks
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private async void startButton_Click(object sender, RoutedEventArgs e)
{
resultsTextBox.Clear();
await CreateMultipleTasksAsync();
resultsTextBox.Text += "\r\n\r\nControl returned to startButton_Click.\r\n";
}
private async Task CreateMultipleTasksAsync()
{
// Declare an HttpClient object, and increase the buffer size. The
// default buffer size is 65,536.
HttpClient client =
new HttpClient() { MaxResponseContentBufferSize = 1000000 };
// Create and start the tasks. As each task finishes, DisplayResults
// displays its length.
Task<int> download1 =
ProcessURLAsync("https://msdn.microsoft.com", client);
Task<int> download2 =
ProcessURLAsync("https://msdn.microsoft.com/en-us/library/hh156528(VS.110).aspx", client);
Task<int> download3 =
ProcessURLAsync("https://msdn.microsoft.com/en-us/library/67w7t67f.aspx", client);
// Await each task.
int length1 = await download1;
int length2 = await download2;
int length3 = await download3;
int total = length1 + length2 + length3;
// Display the total count for the downloaded websites.
resultsTextBox.Text +=
string.Format("\r\n\r\nTotal bytes returned: {0}\r\n", total);
}
async Task<int> ProcessURLAsync(string url, HttpClient client)
{
var byteArray = await client.GetByteArrayAsync(url);
DisplayResults(url, byteArray);
return byteArray.Length;
}
private void DisplayResults(string url, byte[] content)
{
// 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.
var bytes = content.Length;
// Strip off the "http://".
var displayURL = url.Replace("http://", "");
resultsTextBox.Text += string.Format("\n{0,-58} {1,8}", displayURL, bytes);
}
}
}
参照
処理手順
チュートリアル: Async と Await を使用した Web へのアクセス (C# および Visual Basic)
方法: Task.WhenAll を使用して AsyncWalkthrough を拡張する (C# および Visual Basic)