동시에 많은 작업을 수행하지만 사용자 상호 작용에 응답하는 애플리케이션은 여러 스레드를 사용하는 디자인이 필요한 경우가 많습니다. 네임스페이 System.Threading 스는 고성능 다중 스레드 애플리케이션을 만드는 데 필요한 모든 도구를 제공하지만 이러한 도구를 효과적으로 사용하려면 다중 스레드 소프트웨어 엔지니어링에 대한 상당한 경험이 필요합니다. 비교적 간단한 다중 스레드 애플리케이션의 BackgroundWorker 경우 구성 요소는 간단한 솔루션을 제공합니다. 보다 정교한 비동기 애플리케이션의 경우 이벤트 기반 비동기 패턴을 준수하는 클래스를 구현하는 것이 좋습니다.
이벤트 기반 비동기 패턴은 다중 스레드 디자인에 내재된 많은 복잡한 문제를 숨기면서 다중 스레드 애플리케이션의 이점을 제공합니다. 이 패턴을 지원하는 클래스를 사용하면 다음을 수행할 수 있습니다.
애플리케이션을 중단하지 않고 "백그라운드에서" 다운로드 및 데이터베이스 작업과 같은 시간이 많이 걸리는 작업을 수행합니다.
여러 작업을 동시에 실행하여 각 작업이 완료되면 알림을 받습니다.
애플리케이션을 중지("차단")하지 않고 리소스를 사용할 수 있게 될 때까지 기다립니다.
친숙한 이벤트 및 대리자 모델을 사용하여 보류 중인 비동기 작업과 통신합니다. 이벤트 처리기 및 대리자 사용에 대한 자세한 내용은 이벤트를 참조하세요.
이벤트 기반 비동기 패턴을 지원하는 클래스에는 MethodNameAsync라는 메서드가 하나 이상 있습니다. 이러한 메서드는 현재 스레드에서 동일한 작업을 수행하는 동기 버전을 미러링할 수 있습니다. 또한 클래스에 MethodNameCompleted 이벤트가 있을 수 있으며 MethodNameAsyncCancel (또는 단순히 CancelAsync) 메서드가 있을 수 있습니다.
PictureBox 는 이벤트 기반 비동기 패턴을 지원하는 일반적인 구성 요소입니다. 메서드를 호출 Load 하여 이미지를 동기적으로 다운로드할 수 있지만 이미지가 크거나 네트워크 연결이 느린 경우 다운로드 작업이 완료되고 호출 Load 이 반환될 때까지 애플리케이션이 응답하지 않습니다.
이미지를 로드하는 동안 애플리케이션이 계속 실행되도록 하려면 다른 이벤트를 처리하는 것처럼 메서드를 호출 LoadAsync 하고 이벤트를 처리 LoadCompleted 할 수 있습니다. 메서드를 호출하면 다운로드가 LoadAsync 별도의 스레드("백그라운드")에서 진행되는 동안 애플리케이션이 계속 실행됩니다. 이미지 로드 작업이 완료되면 이벤트 처리기가 호출되고 이벤트 처리기가 매개 변수를 검사 AsyncCompletedEventArgs 하여 다운로드가 성공적으로 완료되었는지 확인할 수 있습니다.
이벤트 기반 비동기 패턴을 사용하려면 비동기 작업을 취소할 수 있어야 하며 PictureBox 컨트롤은 해당 CancelAsync 메서드를 사용하여 이 요구 사항을 지원합니다. 호출 CancelAsync 은 보류 중인 다운로드를 중지하는 요청을 제출하고 작업이 취소되면 LoadCompleted 이벤트가 발생합니다.
주의
요청이 이루어진 것처럼 다운로드가 CancelAsync 완료될 수 있으므로 Cancelled 취소 요청을 반영하지 않을 수 있습니다. 이를 경합 상태 라고 하며 다중 스레드 프로그래밍에서 일반적인 문제입니다. 다중 스레드 프로그래밍의 문제에 대한 자세한 내용은 관리되는 스레딩 모범 사례를 참조하세요.
이벤트 기반 비동기 패턴의 특징
이벤트 기반 비동기 패턴은 특정 클래스에서 지원하는 작업의 복잡성에 따라 여러 가지 형태를 취할 수 있습니다. 가장 간단한 클래스에는 단일 MethodNameAsync 메서드와 해당 MethodNameCompleted 이벤트가 있을 수 있습니다. 더 복잡한 클래스에는 각각 해당 MethodNameCompleted 이벤트와 이러한 메서드의 동기 버전이 있는 여러 MethodNameAsync 메서드가 있을 수 있습니다. 클래스는 필요에 따라 각 비동기 메서드에 대한 취소, 진행률 보고 및 증분 결과를 지원할 수 있습니다.
또한 비동기 메서드는 여러 개의 보류 중인 호출(여러 동시 호출)을 지원하여 코드가 다른 보류 중인 작업을 완료하기 전에 여러 번 호출할 수 있도록 할 수 있습니다. 이 상황을 올바르게 처리하려면 애플리케이션이 각 작업의 완료를 추적해야 할 수 있습니다.
이벤트 기반 비동기 패턴의 예
SoundPlayer 및 PictureBox 구성 요소는 이벤트 기반 비동기 패턴의 간단한 구현을 나타냅니다. WebClient 및 BackgroundWorker 구성 요소는 이벤트 기반 비동기 패턴의 더 복잡한 구현을 나타냅니다.
다음은 패턴을 준수하는 예제 클래스 선언입니다.
Public Class AsyncExample
' Synchronous methods.
Public Function Method1(ByVal param As String) As Integer
Public Sub Method2(ByVal param As Double)
' Asynchronous methods.
Overloads Public Sub Method1Async(ByVal param As String)
Overloads Public Sub Method1Async(ByVal param As String, ByVal userState As Object)
Public Event Method1Completed As Method1CompletedEventHandler
Overloads Public Sub Method2Async(ByVal param As Double)
Overloads Public Sub Method2Async(ByVal param As Double, ByVal userState As Object)
Public Event Method2Completed As Method2CompletedEventHandler
Public Sub CancelAsync(ByVal userState As Object)
Public ReadOnly Property IsBusy () As Boolean
' Class implementation not shown.
End Class
public class AsyncExample
{
// Synchronous methods.
public int Method1(string param);
public void Method2(double param);
// Asynchronous methods.
public void Method1Async(string param);
public void Method1Async(string param, object userState);
public event Method1CompletedEventHandler Method1Completed;
public void Method2Async(double param);
public void Method2Async(double param, object userState);
public event Method2CompletedEventHandler Method2Completed;
public void CancelAsync(object userState);
public bool IsBusy { get; }
// Class implementation not shown.
}
가상 AsyncExample
클래스에는 동기 및 비동기 호출을 지원하는 두 가지 메서드가 있습니다. 동기 오버로드는 메서드 호출처럼 동작하고 호출 스레드에서 작업을 실행합니다. 작업이 시간이 많이 걸리는 경우 호출이 반환되기 전에 눈에 띄는 지연이 있을 수 있습니다. 비동기 오버로드는 다른 스레드에서 작업을 시작한 다음 즉시 반환되므로 작업이 "백그라운드에서" 실행되는 동안 호출 스레드를 계속할 수 있습니다.
비동기 메서드 오버로드
비동기 작업에는 단일 호출 및 다중 호출이라는 두 개의 오버로드가 있을 수 있습니다. 이러한 두 폼을 메서드 서명으로 구분할 수 있습니다. 다중 호출 양식에는 추가 매개 변수가 있습니다 userState
. 이 양식을 사용하면 보류 중인 비동기 작업이 완료되기를 기다리지 않고 코드를 여러 번 호출 Method1Async(string param, object userState)
할 수 있습니다. 반면에 이전 호출이 완료되기 전에 Method1Async(string param)
을(를) 호출하려고 하면, 메서드가 InvalidOperationException을(를) 발생시킵니다.
userState
다중 호출 오버로드에 대한 매개 변수를 사용하면 비동기 작업을 구분할 수 있습니다. 각 호출 Method1Async(string param, object userState)
에 대해 고유한 값(예: GUID 또는 해시 코드)을 제공하고 각 작업이 완료되면 이벤트 처리기가 완료 이벤트를 발생시킨 작업의 인스턴스를 확인할 수 있습니다.
보류 중인 작업을 추적하기
다중 호출 오버로드를 사용하는 경우, 코드는 보류 중인 작업에 대한 userState
개체(작업 ID)를 추적해야 합니다. 각 호출에 Method1Async(string param, object userState)
대해 일반적으로 고유한 새 userState
개체를 생성하고 컬렉션에 추가합니다. 이 userState
개체에 해당하는 작업이 완료 이벤트를 발생시킬 때, 완료 메서드 구현은 AsyncCompletedEventArgs.UserState을 검사하고 컬렉션에서 제거합니다. 이러한 방식으로 매개 변수는 userState
작업 ID의 역할을 수행합니다.
비고
다중 호출 오버로드에 대한 userState
호출에서 고유한 값을 제공하도록 주의해야 합니다. 고유하지 않은 작업 ID는 비동기 클래스가 ArgumentException를 던지게 합니다.
보류 중인 작업 취소
완료되기 전에 언제든지 비동기 작업을 취소할 수 있어야 합니다. 이벤트 기반 비동기 패턴을 구현하는 클래스에는 CancelAsync
메서드(비동기 메서드가 하나만 있는 경우) 또는 MethodNameAsyncCancel 메서드(비동기 메서드가 여러 개 있는 경우)가 있습니다.
여러 호출을 허용하는 메서드는 각 작업의 수명을 추적하는 데 사용할 수 있는 매개 변수를 사용합니다 userState
.
CancelAsync
는 userState
특정 보류 중인 작업을 취소할 수 있는 매개 변수를 사용합니다.
한 번에 하나의 보류 중인 작업만 지원하는 메서드(예: Method1Async(string param)
취소할 수 없음).
진행 상황 업데이트 및 점진적 결과 받기
이벤트 기반 비동기 패턴을 준수하는 클래스는 필요에 따라 진행률 및 증분 결과를 추적하기 위한 이벤트를 제공할 수 있습니다. 이 이름은 일반적으로 ProgressChanged
또는 MethodNameProgressChanged으로 이름이 붙여지며, 해당 이벤트 처리기는 ProgressChangedEventArgs 매개 변수를 받습니다.
ProgressChanged
이벤트에 대한 이벤트 처리기는 ProgressChangedEventArgs.ProgressPercentage 속성을 검사하여 비동기 작업이 얼마나 완료되었는지를 백분율로 확인할 수 있습니다. 이 속성은 0에서 100까지의 범위를 가지며, Value 속성을 업데이트하는 데 사용할 수 있습니다. 여러 비동기 작업이 보류 중인 경우, ProgressChangedEventArgs.UserState 속성을 사용하여 어느 작업이 진행 상황을 보고하는지 구분할 수 있습니다.
일부 클래스는 비동기 작업이 진행됨에 따라 증분 결과를 보고할 수 있습니다. 이러한 결과는 파생되는 클래스에 저장되며 파생 ProgressChangedEventArgs 클래스의 속성으로 표시됩니다. 이러한 결과는 ProgressChanged
속성에 액세스하는 것처럼 ProgressPercentage 이벤트의 이벤트 처리기에서 액세스할 수 있습니다. 여러 비동기 작업이 보류 중인 경우 속성을 사용하여 UserState 증분 결과를 보고하는 작업을 구분할 수 있습니다.
참고하십시오
.NET