다음을 통해 공유


여러 비동기 작업을 시작하고 각각 완료될 때마다 처리하기 (Visual Basic)

이를 사용하면 Task.WhenAny여러 작업을 동시에 시작하고 작업이 시작된 순서대로 처리하지 않고 완료될 때 하나씩 처리할 수 있습니다.

다음 예제에서는 쿼리를 사용하여 작업 컬렉션을 만듭니다. 각 태스크는 지정된 웹 사이트의 콘텐츠를 다운로드합니다. while 루프의 각 반복에서 대기 중인 호출은 다운로드를 가장 먼저 완료하는 태스크를 컬렉션에서 반환합니다. 해당 작업은 컬렉션에서 제거되고 처리됩니다. 루프는 컬렉션에 더 이상 태스크가 포함되지 않을 때까지 반복됩니다.

비고

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

예제 다운로드

비동기 샘플: 애플리케이션 미세 조정에서 전체 WPF(Windows Presentation Foundation) 프로젝트를 다운로드한 다음 다음 단계를 수행할 수 있습니다.

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

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

  3. 프로젝트 열기 대화 상자에서 압축을 푼 샘플 코드가 들어 있는 폴더를 연 다음 AsyncFineTuningVB에 대한 솔루션(.sln) 파일을 엽니다.

  4. 솔루션 탐색기에서 ProcessTasksAsTheyFinish 프로젝트의 바로 가기 메뉴를 연 다음 시작 프로젝트로 설정을 선택합니다.

  5. F5 키를 선택하여 프로젝트를 실행합니다.

    프로젝트를 디버깅하지 않고 실행하려면 Ctrl+F5 키를 선택합니다.

  6. 프로젝트를 여러 번 실행하여 다운로드한 길이가 항상 같은 순서로 표시되지 않는지 확인합니다.

프로젝트를 다운로드하지 않으려면 이 항목의 끝에 MainWindow.xaml.vb 파일을 검토할 수 있습니다.

예제를 구축하기

다음은 완료 후 남은 비동기 작업 취소(Visual Basic) 에서 개발된 코드에 추가하고 동일한 UI를 사용하는 예제입니다.

예제를 직접 빌드하려면 단계별로 "예제 다운로드" 섹션의 지침에 따라 시작 프로젝트CancelAfterOneTask를 선택합니다. 이 항목 AccessTheWebAsync 의 변경 내용을 해당 프로젝트의 메서드에 추가합니다. 변경 내용이 별표로 표시됩니다.

CancelAfterOneTask 프로젝트에는 실행 시 작업 컬렉션을 만드는 쿼리가 이미 포함되어 있습니다. 다음 코드에서 ProcessURLAsync에 대한 각 호출은 Task<TResult>가 정수인 TResult을 반환합니다.

Dim downloadTasksQuery As IEnumerable(Of Task(Of Integer)) =  
    From url In urlList Select ProcessURLAsync(url, client, ct)  

프로젝트의 MainWindow.xaml.vb 파일에서 메서드를 다음과 같이 변경합니다 AccessTheWebAsync .

  • Enumerable.ToList을(를) 적용하여 ToArray 대신 쿼리를 실행합니다.

    Dim downloadTasks As List(Of Task(Of Integer)) = downloadTasksQuery.ToList()  
    
  • 컬렉션의 각 작업에 대해 다음 단계를 수행하는 while 루프를 추가합니다.

    1. WhenAny에 대한 호출을 기다려 컬렉션에서 다운로드를 완료할 첫 번째 작업을 식별합니다.

      Dim finishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)  
      
    2. 컬렉션에서 해당 작업을 제거합니다.

      downloadTasks.Remove(finishedTask)  
      
    3. finishedTask 호출에 의해 반환될 ProcessURLAsync를 기다립니다. finishedTask 변수는 Task<TResult>이며, TReturn가 정수인 경우입니다. 작업이 이미 완료되었지만 다음 예제와 같이 다운로드한 웹 사이트의 길이를 검색하기 위해 대기합니다.

      Dim length = Await finishedTask  
      resultsTextBox.Text &= String.Format(vbCrLf & "Length of the downloaded website:  {0}" & vbCrLf, length)  
      

프로젝트를 여러 번 실행하여 다운로드한 길이가 항상 동일한 순서로 표시되지 않는지 확인해야 합니다.

주의

예제에 설명된 대로 루프에서 사용하면 WhenAny 적은 수의 작업이 포함된 문제를 해결할 수 있습니다. 그러나 처리할 작업이 많은 경우 다른 방법이 더 효율적입니다. 자세한 내용 및 예제는 완료되는 작업 처리를 참조하세요.

완성된 예시

다음 코드는 예제에 대한 MainWindow.xaml.vb 파일의 전체 텍스트입니다. 별표는 이 예제에 추가된 요소를 표시합니다.

System.Net.Http에 대한 참조를 추가해야 함을 알아두세요.

비동기 샘플: 애플리케이션 미세 조정에서 프로젝트를 다운로드할 수 있습니다.

' Add an Imports directive and a reference for System.Net.Http.  
Imports System.Net.Http  
  
' Add the following Imports directive for System.Threading.  
Imports System.Threading  
  
Class MainWindow  
  
    ' Declare a System.Threading.CancellationTokenSource.  
    Dim cts As CancellationTokenSource  
  
    Private Async Sub startButton_Click(sender As Object, e As RoutedEventArgs)  
  
        ' Instantiate the CancellationTokenSource.  
        cts = New CancellationTokenSource()  
  
        resultsTextBox.Clear()  
  
        Try  
            Await AccessTheWebAsync(cts.Token)  
            resultsTextBox.Text &= vbCrLf & "Downloads complete."  
  
        Catch ex As OperationCanceledException  
            resultsTextBox.Text &= vbCrLf & "Downloads canceled." & vbCrLf  
  
        Catch ex As Exception  
            resultsTextBox.Text &= vbCrLf & "Downloads failed." & vbCrLf  
        End Try  
  
        ' Set the CancellationTokenSource to Nothing when the download is complete.  
        cts = Nothing  
    End Sub  
  
    ' You can still include a Cancel button if you want to.  
    Private Sub cancelButton_Click(sender As Object, e As RoutedEventArgs)  
  
        If cts IsNot Nothing Then  
            cts.Cancel()  
        End If  
    End Sub  
  
    ' Provide a parameter for the CancellationToken.  
    ' Change the return type to Task because the method has no return statement.  
    Async Function AccessTheWebAsync(ct As CancellationToken) As Task  
  
        Dim client As HttpClient = New HttpClient()  
  
        ' Call SetUpURLList to make a list of web addresses.  
        Dim urlList As List(Of String) = SetUpURLList()  
  
        ' ***Create a query that, when executed, returns a collection of tasks.  
        Dim downloadTasksQuery As IEnumerable(Of Task(Of Integer)) =  
            From url In urlList Select ProcessURLAsync(url, client, ct)  
  
        ' ***Use ToList to execute the query and start the download tasks.
        Dim downloadTasks As List(Of Task(Of Integer)) = downloadTasksQuery.ToList()  
  
        ' ***Add a loop to process the tasks one at a time until none remain.  
        While downloadTasks.Count > 0  
            ' ***Identify the first task that completes.  
            Dim finishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)  
  
            ' ***Remove the selected task from the list so that you don't  
            ' process it more than once.  
            downloadTasks.Remove(finishedTask)  
  
            ' ***Await the first completed task and display the results.  
            Dim length = Await finishedTask  
            resultsTextBox.Text &= String.Format(vbCrLf & "Length of the downloaded website:  {0}" & vbCrLf, length)  
        End While  
  
    End Function  
  
    ' Bundle the processing steps for a website into one async method.  
    Async Function ProcessURLAsync(url As String, client As HttpClient, ct As CancellationToken) As Task(Of Integer)  
  
        ' GetAsync returns a Task(Of HttpResponseMessage).
        Dim response As HttpResponseMessage = Await client.GetAsync(url, ct)  
  
        ' Retrieve the website contents from the HttpResponseMessage.  
        Dim urlContents As Byte() = Await response.Content.ReadAsByteArrayAsync()  
  
        Return urlContents.Length  
    End Function  
  
    ' Add a method that creates a list of web addresses.  
    Private Function SetUpURLList() As List(Of String)  
  
        Dim urls = New List(Of String) From  
            {  
                "https://msdn.microsoft.com",  
                "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  
  
End Class  
  
' Sample output:  
  
' Length of the download:  226093  
' Length of the download:  412588  
' Length of the download:  175490  
' Length of the download:  204890  
' Length of the download:  158855  
' Length of the download:  145790  
' Length of the download:  44908  
' Downloads complete.  

참고하십시오