非同期プログラムにおける制御フロー (Visual Basic)Control Flow in Async Programs (Visual Basic)

Async キーワードと Await キーワードを使用すると、非同期のプログラムの作成と保守をより簡単に行えます。You can write and maintain asynchronous programs more easily by using the Async and Await keywords. ただし、プログラムがどのように動作するかを理解しないと、その結果は予想に反するものになる場合があります。However, the results might surprise you if you don't understand how your program operates. このトピックでは、簡単な非同期プログラムによる制御フローをトレースして、制御があるメソッドから別のメソッドに移るタイミングと、その都度転送される情報について説明します。This topic traces the flow of control through a simple async program to show you when control moves from one method to another and what information is transferred each time.

注意

Async キーワードおよび Await キーワードは、Visual Studio 2012 で導入されました。The Async and Await keywords were introduced in Visual Studio 2012.

一般に、Async 修飾子を使用した非同期コードを含むメソッドをマークします。In general, you mark methods that contain asynchronous code with the Async modifier. async 修飾子でマークされたメソッドでは、Await (Visual Basic) 演算子を使用して、呼び出される非同期処理の終了をメソッドが待機する場所を指定できます。In a method that's marked with an async modifier, you can use an Await (Visual Basic) operator to specify where the method pauses to wait for a called asynchronous process to complete. 詳細については、「Async および Await を使用した非同期プログラミング (Visual Basic)」を参照してください。For more information, see Asynchronous Programming with Async and Await (Visual Basic).

次の例では、非同期メソッドを使用して、指定した Web サイトのコンテンツを文字列としてダウンロードし、その文字列の長さを表示します。The following example uses async methods to download the contents of a specified website as a string and to display the length of the string. この例には、次の 2 つのメソッドが含まれています。The example contains the following two methods.

  • startButton_Click を呼び出して結果を表示する AccessTheWebAsyncstartButton_Click, which calls AccessTheWebAsync and displays the result.

  • Web サイトのコンテンツを文字列としてダウンロードして、その文字列の長さを返す AccessTheWebAsyncAccessTheWebAsync, which downloads the contents of a website as a string and returns the length of the string. AccessTheWebAsync は、非同期 HttpClient メソッドである GetStringAsync(String) を使用してコンテンツをダウンロードします。AccessTheWebAsync uses an asynchronous HttpClient method, GetStringAsync(String), to download the contents.

番号付き表示行はプログラム全体で重要なポイントを示し、プログラムがどのように実行され、マークされている各ポイントで何が発生するかを理解するために役立ちます。Numbered display lines appear at strategic points throughout the program to help you understand how the program runs and to explain what happens at each point that is marked. 表示行には「1」から「6」までのラベルが付けられています。The display lines are labeled "ONE" through "SIX." このラベルは、プログラムがこれらのコード行に到達する順序を表します。The labels represent the order in which the program reaches these lines of code.

次のコードは、プログラムの概要を示します。The following code shows an outline of the program.

Class MainWindow

    Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs) Handles StartButton.Click

        ' ONE
        Dim getLengthTask As Task(Of Integer) = AccessTheWebAsync()

        ' FOUR
        Dim contentLength As Integer = Await getLengthTask

        ' SIX
        ResultsTextBox.Text &=
            vbCrLf & $"Length of the downloaded string: {contentLength}." & vbCrLf

    End Sub

    Async Function AccessTheWebAsync() As Task(Of Integer)

        ' TWO
        Dim client As HttpClient = New HttpClient()
        Dim getStringTask As Task(Of String) =
            client.GetStringAsync("https://msdn.microsoft.com")

        ' THREE
        Dim urlContents As String = Await getStringTask

        ' FIVE
        Return urlContents.Length
    End Function

End Class

「1」から「6」までのそれぞれのラベルの位置は、プログラムの現在の状態に関する情報を表示します。Each of the labeled locations, "ONE" through "SIX," displays information about the current state of the program. 次の出力が生成されます。The following output is produced:

ONE:   Entering startButton_Click.
           Calling AccessTheWebAsync.

TWO:   Entering AccessTheWebAsync.
           Calling HttpClient.GetStringAsync.

THREE: Back in AccessTheWebAsync.
           Task getStringTask is started.
           About to await getStringTask & return a Task<int> to startButton_Click.

FOUR:  Back in startButton_Click.
           Task getLengthTask is started.
           About to await getLengthTask -- no caller to return to.

FIVE:  Back in AccessTheWebAsync.
           Task getStringTask is complete.
           Processing the return statement.
           Exiting from AccessTheWebAsync.

SIX:   Back in startButton_Click.
           Task getLengthTask is finished.
           Result from AccessTheWebAsync is stored in contentLength.
           About to display contentLength and exit.

Length of the downloaded string: 33946.

プログラムをセットアップするSet Up the Program

このトピックで使用するコードは、MSDN からダウンロードするか、または自分でビルドできます。You can download the code that this topic uses from MSDN, or you can build it yourself.

注意

この例を実行するには、Visual Studio 2012 以降と .NET Framework 4.5 以降が、コンピューターにインストールされている必要があります。To run the example, you must have Visual Studio 2012 or newer and the .NET Framework 4.5 or newer installed on your computer.

プログラムをダウンロードするDownload the Program

このトピックのアプリケーションは、「非同期のサンプル:非同期プログラムにおける制御フロー」からダウンロードできます。You can download the application for this topic from Async Sample: Control Flow in Async Programs. 次の手順でプログラムを開いて実行します。The following steps open and run the program.

  1. ダウンロードしたファイルを解凍し、Visual Studio を開始します。Unzip the downloaded file, and then start Visual Studio.

  2. メニュー バーで [ファイル][開く][プロジェクト/ソリューション] の順に選択します。On the menu bar, choose File, Open, Project/Solution.

  3. 解凍したサンプル コードが含まれるフォルダーに移動し、ソリューション (.sln) ファイルを開き、F5 キーを押してプロジェクトをビルドし、実行します。Navigate to the folder that holds the unzipped sample code, open the solution (.sln) file, and then choose the F5 key to build and run the project.

プログラムを手動でビルドするBuild the Program Yourself

次の Windows Presentation Foundation (WPF) プロジェクトには、このトピックのコード例が含まれています。The following Windows Presentation Foundation (WPF) project contains the code example for this topic.

このプロジェクトを実行するには、次の手順を実行します。To run the project, perform the following steps:

  1. Visual Studio を起動します。Start Visual Studio.

  2. メニュー バーで、 [ファイル][新規作成][プロジェクト] の順にクリックします。On the menu bar, choose File, New, Project.

    [新しいプロジェクト] ダイアログ ボックスが表示されます。The New Project dialog box opens.

  3. [インストールされたテンプレート] ペインで、 [Visual Basic] を選択し、プロジェクトの種類の一覧で [WPF アプリケーション] を選択します。In the Installed Templates pane, choose Visual Basic, and then choose WPF Application from the list of project types.

  4. プロジェクトの名前として「AsyncTracer」と入力し、 [OK] をクリックします。Enter AsyncTracer as the name of the project, and then choose the OK button.

    ソリューション エクスプローラーに新しいプロジェクトが表示されます。The new project appears in Solution Explorer.

  5. Visual Studio コード エディターで、 [MainWindow.xaml] タブをクリックします。In the Visual Studio Code Editor, choose the MainWindow.xaml tab.

    タブが表示されない場合は、ソリューション エクスプローラーで MainWindow.xaml のショートカット メニューを開き、 [コードの表示] を選択します。If the tab isn’t visible, open the shortcut menu for MainWindow.xaml in Solution Explorer, and then choose View Code.

  6. MainWindow.xaml の XAML ビューで、コードを次のコードに置き換えます。In the XAML view of MainWindow.xaml, replace the code with the following code.

    <Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="MainWindow"
        Title="Control Flow Trace" Height="350" Width="525">
        <Grid>
            <Button x:Name="StartButton" Content="Start" HorizontalAlignment="Left" Margin="221,10,0,0" VerticalAlignment="Top" Width="75"/>
            <TextBox x:Name="ResultsTextBox" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Bottom" Width="510" Height="265" FontFamily="Lucida Console" FontSize="10" VerticalScrollBarVisibility="Visible" d:LayoutOverrides="HorizontalMargin"/>
    
        </Grid>
    </Window>
    

    テキスト ボックスとボタンを含む簡単なウィンドウが、MainWindow.xaml のデザイン ビューに表示されます。A simple window that contains a text box and a button appears in the Design view of MainWindow.xaml.

  7. System.Net.Http への参照を追加します。Add a reference for System.Net.Http.

  8. ソリューション エクスプローラーで MainWindow.xaml.vb のショートカット メニューを開き、 [コードの表示] を選択します。In Solution Explorer, open the shortcut menu for MainWindow.xaml.vb, and then choose View Code.

  9. MainWindow.xaml.vb のコードを次のコードに置き換えます。In MainWindow.xaml.vb , replace the code with the following code.

    ' Add an Imports statement and a reference for System.Net.Http.
    Imports System.Net.Http
    
    Class MainWindow
    
        Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs) Handles StartButton.Click
    
            ' The display lines in the example lead you through the control shifts.
            ResultsTextBox.Text &= "ONE:   Entering StartButton_Click." & vbCrLf &
                "           Calling AccessTheWebAsync." & vbCrLf
    
            Dim getLengthTask As Task(Of Integer) = AccessTheWebAsync()
    
            ResultsTextBox.Text &= vbCrLf & "FOUR:  Back in StartButton_Click." & vbCrLf &
                "           Task getLengthTask is started." & vbCrLf &
                "           About to await getLengthTask -- no caller to return to." & vbCrLf
    
            Dim contentLength As Integer = Await getLengthTask
    
            ResultsTextBox.Text &= vbCrLf & "SIX:   Back in StartButton_Click." & vbCrLf &
                "           Task getLengthTask is finished." & vbCrLf &
                "           Result from AccessTheWebAsync is stored in contentLength." & vbCrLf &
                "           About to display contentLength and exit." & vbCrLf
    
            ResultsTextBox.Text &=
                String.Format(vbCrLf & "Length of the downloaded string: {0}." & vbCrLf, contentLength)
        End Sub
    
        Async Function AccessTheWebAsync() As Task(Of Integer)
    
            ResultsTextBox.Text &= vbCrLf & "TWO:   Entering AccessTheWebAsync."
    
            ' Declare an HttpClient object.
            Dim client As HttpClient = New HttpClient()
    
            ResultsTextBox.Text &= vbCrLf & "           Calling HttpClient.GetStringAsync." & vbCrLf
    
            ' GetStringAsync returns a Task(Of String).
            Dim getStringTask As Task(Of String) = client.GetStringAsync("https://msdn.microsoft.com")
    
            ResultsTextBox.Text &= vbCrLf & "THREE: Back in AccessTheWebAsync." & vbCrLf &
                "           Task getStringTask is started."
    
            ' AccessTheWebAsync can continue to work until getStringTask is awaited.
    
            ResultsTextBox.Text &=
                vbCrLf & "           About to await getStringTask & return a Task(Of Integer) to StartButton_Click." & vbCrLf
    
            ' Retrieve the website contents when task is complete.
            Dim urlContents As String = Await getStringTask
    
            ResultsTextBox.Text &= vbCrLf & "FIVE:  Back in AccessTheWebAsync." &
                vbCrLf & "           Task getStringTask is complete." &
                vbCrLf & "           Processing the return statement." &
                vbCrLf & "           Exiting from AccessTheWebAsync." & vbCrLf
    
            Return urlContents.Length
        End Function
    
    End Class
    
  10. F5 キーを押してプログラムを実行し、 [Start] を複数回クリックします。Choose the F5 key to run the program, and then choose the Start button.

    次の出力が表示されます。The following output should appear:

    ONE:   Entering startButton_Click.
               Calling AccessTheWebAsync.
    
    TWO:   Entering AccessTheWebAsync.
               Calling HttpClient.GetStringAsync.
    
    THREE: Back in AccessTheWebAsync.
               Task getStringTask is started.
               About to await getStringTask & return a Task<int> to startButton_Click.
    
    FOUR:  Back in startButton_Click.
               Task getLengthTask is started.
               About to await getLengthTask -- no caller to return to.
    
    FIVE:  Back in AccessTheWebAsync.
               Task getStringTask is complete.
               Processing the return statement.
               Exiting from AccessTheWebAsync.
    
    SIX:   Back in startButton_Click.
               Task getLengthTask is finished.
               Result from AccessTheWebAsync is stored in contentLength.
               About to display contentLength and exit.
    
    Length of the downloaded string: 33946.
    

プログラムのトレースTrace the Program

手順 1. および 2.Steps ONE and TWO

startButton_ClickAccessTheWebAsync を呼び出し、AccessTheWebAsync が非同期 HttpClient メソッド GetStringAsync(String) を呼び出すと、最初の 2 行の表示行がパスをトレースします。The first two display lines trace the path as startButton_Click calls AccessTheWebAsync, and AccessTheWebAsync calls the asynchronous HttpClient method GetStringAsync(String). 次の図は、メソッドからメソッドへの呼び出しを示しています。The following image outlines the calls from method to method.

手順 1. および 2.Steps ONE and TWO

AccessTheWebAsyncclient.GetStringAsync の戻り値の型はどちらも Task<TResult> です。The return type of both AccessTheWebAsync and client.GetStringAsync is Task<TResult>. AccessTheWebAsync では、TResult は整数です。For AccessTheWebAsync, TResult is an integer. GetStringAsync では、TResult は文字列です。For GetStringAsync, TResult is a string. 非同期メソッドの戻り値の型について詳しくは、「非同期の戻り値の型 (Visual Basic)」を参照してください。For more information about async method return types, see Async Return Types (Visual Basic).

タスクを返す非同期のメソッドは、制御が呼び出し元に戻ると、タスク インスタンスを返します。A task-returning async method returns a task instance when control shifts back to the caller. Await 演算子が呼び出されたメソッドで実行されるか、または呼び出されたメソッドが終了すると、非同期メソッドから呼び出し元に制御が戻ります。Control returns from an async method to its caller either when an Await operator is encountered in the called method or when the called method ends. 「3」から「6」のラベルの付いた表示行はこのプロセスの部分をトレースします。The display lines that are labeled "THREE" through "SIX" trace this part of the process.

手順 3.Step THREE

AccessTheWebAsync で非同期メソッド GetStringAsync(String) が呼び出され、ターゲットの Web ページのコンテンツがダウンロードされます。In AccessTheWebAsync, the asynchronous method GetStringAsync(String) is called to download the contents of the target webpage. client.GetStringAsync が制御を返すと、AccessTheWebAsync から client.GetStringAsync に制御が戻ります。Control returns from client.GetStringAsync to AccessTheWebAsync when client.GetStringAsync returns.

client.GetStringAsync メソッドは、getStringTaskAccessTheWebAsync 変数に割り当てる文字列のタスクを返します。The client.GetStringAsync method returns a task of string that’s assigned to the getStringTask variable in AccessTheWebAsync. プログラム例の次の行は、client.GetStringAsync の呼び出しと割り当てを示しています。The following line in the example program shows the call to client.GetStringAsync and the assignment.

Dim getStringTask As Task(Of String) = client.GetStringAsync("https://msdn.microsoft.com")

このタスクは client.GetStringAsync により実際の文字列が最終的に生成される約束と見なすことができます。You can think of the task as a promise by client.GetStringAsync to produce an actual string eventually. AccessTheWebAsync には client.GetStringAsync から約束された文字列に依存しない処理がある場合、その処理は client.GetStringAsync を待機している間は、続行できます。In the meantime, if AccessTheWebAsync has work to do that doesn't depend on the promised string from client.GetStringAsync, that work can continue while client.GetStringAsync waits. この例では、"THREE" のラベルの付いた行の出力は、独立した処理を行う機会を表します。In the example, the following lines of output, which are labeled "THREE," represent the opportunity to do independent work

THREE: Back in AccessTheWebAsync.
           Task getStringTask is started.
           About to await getStringTask & return a Task<int> to startButton_Click.

次のステートメントは AccessTheWebAsync が待機中の場合 getStringTask の進行を中断します。The following statement suspends progress in AccessTheWebAsync when getStringTask is awaited.

Dim urlContents As String = Await getStringTask

次の図は client.GetStringAsync から getStringTask への割り当てへの制御フロー、および getStringTask の作成から Await 演算子のアプリケーションへの制御フローを示しています。The following image shows the flow of control from client.GetStringAsync to the assignment to getStringTask and from the creation of getStringTask to the application of an Await operator.

手順 3.Step THREE

await 式は AccessTheWebAsync が制御を返すまで client.GetStringAsync を中断します。The await expression suspends AccessTheWebAsync until client.GetStringAsync returns. その間、コントロールは AccessTheWebAsync の呼び出し元である startButton_Click に戻されます。In the meantime, control returns to the caller of AccessTheWebAsync, startButton_Click.

注意

通常、直ちに非同期メソッドへの呼び出しの待機状態となります。Typically, you await the call to an asynchronous method immediately. たとえば、次の割り当てで、getStringTask を作成してそれを待機する前のコードを置き換えることができます: Dim urlContents As String = Await client.GetStringAsync("https://msdn.microsoft.com")For example, the following assignment could replace the previous code that creates and then awaits getStringTask: Dim urlContents As String = Await client.GetStringAsync("https://msdn.microsoft.com")

このトピックでは、await 演算子が後で適用され、プログラムでの制御フローを示す出力行を格納します。In this topic, the await operator is applied later to accommodate the output lines that mark the flow of control through the program.

手順 4.Step FOUR

AccessTheWebAsync の宣言された戻り値の型は、Task(Of Integer) です。The declared return type of AccessTheWebAsync is Task(Of Integer). したがって、AccessTheWebAsync が中断されると、startButton_Click に整数のタスクを返します。Therefore, when AccessTheWebAsync is suspended, it returns a task of integer to startButton_Click. 返されたタスクは getStringTask ではないことに注意する必要があります。You should understand that the returned task isn’t getStringTask. 返されたタスクは、中断されたメソッド AccessTheWebAsync での未処理を表す、整数の新しいタスクです。The returned task is a new task of integer that represents what remains to be done in the suspended method, AccessTheWebAsync. これにより、タスクが完了したときに AccessTheWebAsync が整数を生成することが保証されます。The task is a promise from AccessTheWebAsync to produce an integer when the task is complete.

次のステートメントはこのタスクを getLengthTask 変数に割り当てます。The following statement assigns this task to the getLengthTask variable.

Dim getLengthTask As Task(Of Integer) = AccessTheWebAsync()

AccessTheWebAsync と同様に、startButton_Click は、非同期タスク (getLengthTask) の結果に依存しない処理を、タスクが待機するまで続行できます。As in AccessTheWebAsync, startButton_Click can continue with work that doesn’t depend on the results of the asynchronous task (getLengthTask) until the task is awaited. 次の出力行はその処理を表します。The following output lines represent that work:

FOUR:  Back in startButton_Click.
           Task getLengthTask is started.
           About to await getLengthTask -- no caller to return to.

startButton_Click が待機すると、getLengthTask の進行は中断します。Progress in startButton_Click is suspended when getLengthTask is awaited. 次の代入ステートメントは、startButton_Click が完了するまで AccessTheWebAsync を中断します。The following assignment statement suspends startButton_Click until AccessTheWebAsync is complete.

Dim contentLength As Integer = Await getLengthTask

次の図で、矢印は AccessTheWebAsync の await 式から getLengthTask への値の割り当てへの制御のフロー、および startButton_Click が待機するまでの getLengthTask の通常の処理を示しています。In the following illustration, the arrows show the flow of control from the await expression in AccessTheWebAsync to the assignment of a value to getLengthTask, followed by normal processing in startButton_Click until getLengthTask is awaited.

手順 4.Step FOUR

手順 5.Step FIVE

client.GetStringAsync が終了を通知すると、AccessTheWebAsync の処理は中断から解放され、await ステートメントを越えて続行できます。When client.GetStringAsync signals that it’s complete, processing in AccessTheWebAsync is released from suspension and can continue past the await statement. 次の出力行は、処理の再開を表します。The following lines of output represent the resumption of processing:

FIVE:  Back in AccessTheWebAsync.
           Task getStringTask is complete.
           Processing the return statement.
           Exiting from AccessTheWebAsync.

return ステートメントのオペランド urlContents.LengthAccessTheWebAsync が返すタスクに格納されます。The operand of the return statement, urlContents.Length, is stored in the task that AccessTheWebAsync returns. await 式はその値を getLengthTaskstartButton_Click から取得します。The await expression retrieves that value from getLengthTask in startButton_Click.

次の図は、client.GetStringAsync (および getStringTask) が完了した後の制御の移動を示します。The following image shows the transfer of control after client.GetStringAsync (and getStringTask) are complete.

手順 5.Step FIVE

AccessTheWebAsync は完了するまで実行され、完了を待機していた startButton_Click に制御が戻ります。AccessTheWebAsync runs to completion, and control returns to startButton_Click, which is awaiting the completion.

手順 6.Step SIX

AccessTheWebAsync が終了を通知すると、処理は startButton_Async の await ステートメントを越えて続行できます。When AccessTheWebAsync signals that it’s complete, processing can continue past the await statement in startButton_Async. 実際、プログラムはそれ以上行うことがありません。In fact, the program has nothing more to do.

次の出力行は、startButton_Async の処理の再開を表します。The following lines of output represent the resumption of processing in startButton_Async:

SIX:   Back in startButton_Click.
           Task getLengthTask is finished.
           Result from AccessTheWebAsync is stored in contentLength.
           About to display contentLength and exit.

await 式は getLengthTask から AccessTheWebAsync の return ステートメントのオペランドである整数値を取得します。The await expression retrieves from getLengthTask the integer value that’s the operand of the return statement in AccessTheWebAsync. 次のステートメントはその値を contentLength 変数に割り当てます。The following statement assigns that value to the contentLength variable.

Dim contentLength As Integer = Await getLengthTask

次の図は AccessTheWebAsync から startButton_Click に制御が戻ることを示しています。The following image shows the return of control from AccessTheWebAsync to startButton_Click.

手順 6.Step SIX

関連項目See also