메서드를 Task.WhenAny 함께 CancellationToken사용하면 하나의 작업이 완료되면 나머지 작업을 모두 취소할 수 있습니다. 메서드는 WhenAny
작업 컬렉션인 인수를 사용합니다. 메서드는 모든 작업을 시작하고 단일 작업을 반환합니다. 컬렉션의 모든 작업이 완료되면 단일 작업이 완료됩니다.
이 예제는 WhenAny
와 함께 취소 토큰을 사용하여 작업 컬렉션 중 가장 먼저 완료되는 작업을 선택하고, 나머지 작업은 취소하는 방법을 보여줍니다. 각 작업은 웹 사이트의 콘텐츠를 다운로드합니다. 이 예제에서는 완료할 첫 번째 다운로드의 콘텐츠 길이를 표시하고 다른 다운로드를 취소합니다.
비고
예제를 실행하려면 Visual Studio 2012 이상과 .NET Framework 4.5 이상이 컴퓨터에 설치되어 있어야 합니다.
예제 다운로드
비동기 샘플: 애플리케이션 미세 조정에서 전체 WPF(Windows Presentation Foundation) 프로젝트를 다운로드한 다음 다음 단계를 수행할 수 있습니다.
다운로드한 파일의 압축을 해제한 다음 Visual Studio를 시작합니다.
메뉴 모음에서 파일, 열기, 프로젝트/솔루션을 선택합니다.
프로젝트 열기 대화 상자에서 압축을 푼 샘플 코드가 들어 있는 폴더를 연 다음 AsyncFineTuningVB에 대한 솔루션(.sln) 파일을 엽니다.
솔루션 탐색기에서 CancelAfterOneTask 프로젝트의 바로 가기 메뉴를 열고 시작 프로젝트로 설정을 선택합니다.
F5 키를 선택하여 프로젝트를 실행합니다.
프로젝트를 디버깅하지 않고 실행하려면 Ctrl+F5 키를 선택합니다.
프로그램을 여러 번 실행하여 다른 다운로드가 먼저 완료되는지 확인합니다.
프로젝트를 다운로드하지 않으려면 이 항목의 끝에 MainWindow.xaml.vb 파일을 검토할 수 있습니다.
예제를 구축하기
이 항목의 예제는 비동기 작업 취소 또는 작업 목록에서 개발된 프로젝트에 추가되어 작업 목록을 취소합니다. 이 예제에서는 취소 단추가 명시적으로 사용되지는 않지만 동일한 UI를 사용합니다.
예제를 직접 빌드하려면 단계별로 "예제 다운로드" 섹션의 지침에 따라 시작 프로젝트로 CancelAListOfTasks를 선택합니다. 이 항목의 변경 내용을 해당 프로젝트에 추가합니다.
CancelAListOfTasks 프로젝트의 MainWindow.xaml.vb 파일에서 루프 내 각 웹 사이트의 처리 단계를 다음 비동기 메서드로 이동하여 작업을 시작합니다.
' ***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
이 예제에서는 AccessTheWebAsync
쿼리와 ToArray 메서드 및 WhenAny
메서드를 사용하여 작업 배열을 생성하고 시작합니다.
WhenAny
을 배열에 적용하면 대기 시 배열의 태스크들 중 가장 먼저 완료되는 태스크로 평가되는 단일 작업이 반환됩니다.
AccessTheWebAsync
에서 다음을 변경합니다. 별표는 코드 파일의 변경 내용을 표시합니다.
루프를 주석 처리하거나 삭제합니다.
실행할 때 제네릭 태스크 컬렉션을 생성하는 쿼리를 만듭니다. 각 호출은
ProcessURLAsync
를 호출하며, Task<TResult>는TResult
의 반환값을 나타내며,TResult
는 정수입니다.' ***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)
쿼리를 실행하고 작업을 시작하도록 호출
ToArray
합니다. 다음 단계에서WhenAny
메서드를 적용하면ToArray
을 사용하지 않고 쿼리를 실행하고 작업을 시작합니다. 하지만 다른 메서드에서는 이렇게 실행되지 않을 수 있습니다. 가장 안전한 방법은 쿼리를 명시적으로 강제로 실행하는 것입니다.' ***Use ToArray to execute the query and start the download tasks. Dim downloadTasks As Task(Of Integer)() = downloadTasksQuery.ToArray()
작업 모음에 대해 콜 기능을 사용하여
WhenAny
를 호출합니다.WhenAny
는Task(Of Task(Of Integer))
또는Task<Task<int>>
를 반환합니다. 즉,WhenAny
는 대기할 때 단일Task(Of Integer)
또는Task<int>
로 평가되는 작업을 반환합니다. 이 단일 작업은 컬렉션에서 완료할 첫 번째 작업입니다. 먼저 완료된 작업이 에 할당됩니다finishedTask
.finishedTask
의 형식은 정수인 Task<TResult>의 위치이며, 이는TResult
의 반환 형식이ProcessURLAsync
이기 때문입니다.' ***Call WhenAny and then await the result. The task that finishes ' first is assigned to finishedTask. Dim finishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)
이 예제에서는 먼저 완료되는 작업에만 관심이 있습니다. 따라서 나머지 작업을 취소하는 데 사용합니다 CancellationTokenSource.Cancel .
' ***Cancel the rest of the downloads. You just want the first one. cts.Cancel()
마지막으로 다운로드한 콘텐츠의 길이를 검색하기 위해 기다립니다
finishedTask
.Dim length = Await finishedTask resultsTextBox.Text &= vbCrLf & $"Length of the downloaded website: {length}" & vbCrLf
프로그램을 여러 번 실행하여 다른 다운로드가 먼저 완료되는지 확인합니다.
완성된 예시
다음 코드는 예제에 대한 전체 MainWindow.xaml.vb 또는 MainWindow.xaml.cs 파일입니다. 별표는 이 예제에 추가된 요소를 표시합니다.
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 & "Download complete."
Catch ex As OperationCanceledException
resultsTextBox.Text &= vbCrLf & "Download canceled." & vbCrLf
Catch ex As Exception
resultsTextBox.Text &= vbCrLf & "Download 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()
'' Comment out or delete the loop.
''For Each url In urlList
'' ' GetAsync returns a Task(Of HttpResponseMessage).
'' ' Argument ct carries the message if the Cancel button is chosen.
'' ' Note that the Cancel button can cancel all remaining downloads.
'' Dim response As HttpResponseMessage = Await client.GetAsync(url, ct)
'' ' Retrieve the website contents from the HttpResponseMessage.
'' Dim urlContents As Byte() = Await response.Content.ReadAsByteArrayAsync()
'' resultsTextBox.Text &=
'' vbCrLf & $"Length of the downloaded string: {urlContents.Length}." & vbCrLf
''Next
' ***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 ToArray to execute the query and start the download tasks.
Dim downloadTasks As Task(Of Integer)() = downloadTasksQuery.ToArray()
' ***Call WhenAny and then await the result. The task that finishes
' first is assigned to finishedTask.
Dim finishedTask As Task(Of Integer) = Await Task.WhenAny(downloadTasks)
' ***Cancel the rest of the downloads. You just want the first one.
cts.Cancel()
' ***Await the first completed task and display the results
' Run the program several times to demonstrate that different
' websites can finish first.
Dim length = Await finishedTask
resultsTextBox.Text &= vbCrLf & $"Length of the downloaded website: {length}" & vbCrLf
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 downloaded website: 158856
' Download complete.
참고하십시오
.NET