다음을 통해 공유


비동기 프로그램의 제어 흐름(Visual Basic)

및 키워드를 사용하여 AsyncAwait 비동기 프로그램을 더 쉽게 작성하고 유지 관리할 수 있습니다. 그러나 프로그램이 작동하는 방식을 이해하지 못하면 결과가 놀랄 수 있습니다. 이 항목에서는 간단한 비동기 프로그램을 통해 제어 흐름을 추적하여 컨트롤이 한 메서드에서 다른 메서드로 이동할 때와 매번 전송되는 정보를 보여 줍니다.

비고

AsyncAwait 키워드는 Visual Studio 2012에서 도입되었습니다.

일반적으로 비동기 코드가 포함된 메서드를 비동 기 한정자로 표시합니다. 비동기 한정자로 표시된 메서드에서 Await(Visual Basic) 연산자를 사용하여 호출된 비동기 프로세스가 완료되기를 기다리도록 메서드가 일시 중지되는 위치를 지정할 수 있습니다. 자세한 내용은 Async 및 Await를 사용한 비동기 프로그래밍(Visual Basic)을 참조하세요.

다음 예제에서는 비동기 메서드를 사용하여 지정된 웹 사이트의 콘텐츠를 문자열로 다운로드하고 문자열의 길이를 표시합니다. 이 예제에는 다음 두 가지 메서드가 포함되어 있습니다.

  • startButton_ClickAccessTheWebAsync을 호출하고 결과를 표시합니다.

  • AccessTheWebAsync웹 사이트의 콘텐츠를 문자열로 다운로드하고 문자열의 길이를 반환하는 입니다. AccessTheWebAsync는 비동기 HttpClient 메서드 GetStringAsync(String)를 사용하여 콘텐츠를 다운로드합니다.

번호가 매겨진 표시줄은 프로그램 전체의 전략적 지점에 표시되어 프로그램이 실행되는 방식을 이해하고 표시된 각 지점에서 발생하는 작업을 설명하는 데 도움이 됩니다. 표시줄은 "ONE"에서 "SIX"로 레이블이 지정됩니다. 레이블은 프로그램이 이러한 코드 줄에 도달하는 순서를 나타냅니다.

다음 코드는 프로그램의 개요를 보여줍니다.

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://learn.microsoft.com")

        ' THREE
        Dim urlContents As String = Await getStringTask

        ' FIVE
        Return urlContents.Length
    End Function

End Class

레이블이 지정된 각 위치인 "ONE"에서 "SIX"는 프로그램의 현재 상태에 대한 정보를 표시합니다. 다음 출력이 생성됩니다.

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.

프로그램 설정

이 항목이 MSDN에서 사용하는 코드를 다운로드하거나 직접 빌드할 수 있습니다.

비고

예제를 실행하려면 Visual Studio 2012 이상과 .NET Framework 4.5 이상이 컴퓨터에 설치되어 있어야 합니다.

프로그램 다운로드

비동기 프로그램에서 제어 흐름의 비동기 샘플 이 항목에 대한 애플리케이션을 다운로드할 수 있습니다. 다음 단계에서는 프로그램을 열고 실행합니다.

  1. 다운로드한 파일의 압축을 풀고 Visual Studio를 시작합니다.

  2. 메뉴 모음에서 파일, 열기, 프로젝트/솔루션을 선택합니다.

  3. 압축을 푼 샘플 코드가 있는 폴더로 이동하고 솔루션(.sln) 파일을 연 다음 F5 키를 선택하여 프로젝트를 빌드하고 실행합니다.

직접 프로그램 빌드

다음 WPF(Windows Presentation Foundation) 프로젝트에는 이 항목의 코드 예제가 포함되어 있습니다.

프로젝트를 실행하려면 다음 단계를 수행합니다.

  1. Visual Studio를 시작합니다.

  2. 메뉴 모음에서 파일, 새로 만들기, 프로젝트를 선택합니다.

    새 프로젝트 대화 상자가 열립니다.

  3. 설치된 템플릿 창에서 Visual Basic을 선택한 다음, 프로젝트 형식 목록에서 WPF 애플리케이션을 선택합니다.

  4. 프로젝트의 이름으로 입력 AsyncTracer 한 다음 확인 단추를 선택합니다.

    새 프로젝트가 솔루션 탐색기에 나타납니다.

  5. Visual Studio Code 편집기에서 MainWindow.xaml 탭을 선택합니다.

    탭이 표시되지 않으면 솔루션 탐색기에서 MainWindow.xaml의 바로 가기 메뉴를 열고 코드 보기를 선택합니다.

  6. MainWindow.xaml의 XAML 보기에서 코드를 다음 코드로 바꿉니다.

    <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의 디자인 보기에 텍스트 상자와 단추가 포함된 간단한 창이 나타납니다.

  7. 에 대한 참조를 추가합니다 System.Net.Http.

  8. 솔루션 탐색기에서 MainWindow.xaml.vb 대한 바로 가기 메뉴를 연 다음 코드 보기를 선택합니다.

  9. MainWindow.xaml.vb 코드를 다음 코드로 바꿉다.

    ' 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://learn.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 키를 선택하여 프로그램을 실행한 다음 시작 단추를 선택합니다.

    다음 출력이 표시됩니다.

    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.
    

프로그램 추적

1단계와 2단계

처음 두 표시 줄은 startButton_ClickAccessTheWebAsync을 호출하고, AccessTheWebAsync이 비동기 메서드 HttpClient, GetStringAsync(String)을 호출하는 경로를 추적합니다. 다음 이미지는 메서드에서 메서드로의 호출을 간략하게 설명합니다.

1단계 및 2단계

둘 다 AccessTheWebAsyncclient.GetStringAsync의 반환 형식은 Task<TResult>입니다. 의 경우 AccessTheWebAsyncTResult는 정수입니다. 의 경우 GetStringAsyncTResult는 문자열입니다. 비동기 메서드 반환 형식에 대한 자세한 내용은 비동기 반환 형식(Visual Basic)을 참조하세요.

컨트롤이 호출자로 다시 이동하면 태스크 반환 비동기 메서드가 작업 인스턴스를 반환합니다. 호출된 메서드에서 연산자가 발견되거나 호출된 메서드가 종료될 때 Await 컨트롤이 비동기 메서드에서 호출자로 반환됩니다. "THREE"에서 "SIX"로 레이블이 지정된 표시줄은 프로세스의 이 부분을 추적합니다.

3단계

에서 AccessTheWebAsync비동기 메서드 GetStringAsync(String) 는 대상 웹 페이지의 콘텐츠를 다운로드하기 위해 호출됩니다. client.GetStringAsync 가 반환되면 제어가 AccessTheWebAsync 에서 client.GetStringAsync 로 반환됩니다.

client.GetStringAsync 메서드는 문자열 작업을 반환하며, 이는 getStringTask에서 AccessTheWebAsync 변수에 할당됩니다. 예제 프로그램의 다음 줄에는 호출 client.GetStringAsync 및 할당이 표시됩니다.

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

작업을 client.GetStringAsync 가 결국 실제 문자열을 생성할 것이라는 약속으로 생각할 수 있습니다. 그 동안 약속된 문자열AccessTheWebAsync에 의존하지 않는 작업이 있는 경우 client.GetStringAsync 대기하는 동안 client.GetStringAsync 해당 작업을 계속할 수 있습니다. 이 예제에서 "THREE"라는 레이블이 지정된 다음 출력 줄은 독립적인 작업을 수행할 수 있는 기회를 나타냅니다.

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

다음 문은 AccessTheWebAsync가 대기 중일 때 getStringTask의 진행을 일시 중단합니다.

Dim urlContents As String = Await getStringTask

다음 이미지는 client.GetStringAsync에서 getStringTask 할당으로의 제어 흐름과 getStringTask 생성에서 Await 연산자의 적용으로의 흐름을 보여줍니다.

3단계

await 식은 AccessTheWebAsync을 일시 중단하고 client.GetStringAsync이 반환될 때까지 기다립니다. 그 동안에 컨트롤이 AccessTheWebAsync 호출자에게 반환됩니다.

비고

일반적으로 비동기 메서드에 대한 호출을 즉시 기다립니다. 예를 들어 다음 할당은 만든 다음 대기하는 이전 코드를 대체할 수 있습니다.getStringTaskDim urlContents As String = Await client.GetStringAsync("https://learn.microsoft.com")

이 항목에서 await 연산자는 나중에 프로그램을 통해 제어 흐름을 표시하는 출력 줄을 수용하기 위해 적용됩니다.

4단계

선언된 반환 형식 AccessTheWebAsync 은 .입니다 Task(Of Integer). 따라서 AccessTheWebAsync 일시 중단되면 정수 작업을 반환합니다 startButton_Click. 반납된 작업이 getStringTask이 아님을 이해해야 합니다. 반환된 작업은 일시 중단된 메서드 AccessTheWebAsync에서 수행할 작업을 나타내는 정수의 새 작업입니다. 태스크는 AccessTheWebAsync이 작업이 완료되면 정수를 생성할 것을 약속합니다.

다음 문은 이 작업을 변수에 getLengthTask 할당합니다.

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

마찬가지로 AccessTheWebAsync, 비동기 작업(startButton_Click)이 완료될 때까지 getLengthTask 작업은 기다리지 않고 계속 수행할 수 있습니다. 다음 출력 줄은 해당 작업을 나타냅니다.

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

startButton_Click을(를) 기다리는 동안 getLengthTask 진행이 일시 중단됩니다. 다음 할당문은 startButton_ClickAccessTheWebAsync가 완료될 때까지 일시 중단합니다.

Dim contentLength As Integer = Await getLengthTask

다음 그림에서 화살표는 await 식 AccessTheWebAsync에서 getLengthTask에 값이 할당되는 것으로 이어지는 제어 흐름을 보여주며, startButton_Click에서 getLengthTask이 대기되기 전까지 정상적으로 처리됩니다.

4단계

5단계

client.GetStringAsync가 완료되었음을 알리면, AccessTheWebAsync에서의 처리가 일시 중단에서 해제되어 await 문을 지나 계속 진행할 수 있습니다. 다음 출력 줄은 처리 재개를 나타냅니다.

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

반환문의 피연산자인 urlContents.LengthAccessTheWebAsync가 반환하는 작업에 저장됩니다. await 식은 getLengthTask에서 startButton_Click의 값을 검색합니다.

다음 이미지는 client.GetStringAsync (및 getStringTask)가 완료된 후에 제어가 전송되는 모습을 보여 줍니다.

5단계

AccessTheWebAsync는 완전히 실행되며, 컨트롤은 완료를 기다리는 startButton_Click로 돌아갑니다.

6단계

AccessTheWebAsync가 완료되었다는 신호를 보내면 startButton_Async에서 await 문을 지나 처리가 계속될 수 있습니다. 사실, 프로그램은 더 이상 할 일이 없습니다.

다음 출력 줄은 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의 반환 문의 피연산자인 정수 값을 가져옵니다. 다음 문은 해당 값을 변수에 contentLength 할당합니다.

Dim contentLength As Integer = Await getLengthTask

다음 이미지는 AccessTheWebAsync에서 startButton_Click로 컨트롤이 돌아가는 것을 보여줍니다.

6단계

참고하십시오