Share via


이벤트 기반 비동기 패턴 개요

업데이트: 2007년 11월

많은 작업을 수행하는 동시에 사용자와의 상호 작용에 빠르게 응답하는 응용 프로그램에는 여러 스레드를 사용하는 디자인이 필요한 경우가 많습니다. System.Threading 네임스페이스는 고성능 다중 스레드 응용 프로그램을 만드는 데 필요한 모든 도구를 제공하지만 이 도구를 효과적으로 사용하려면 다중 스레드 소프트웨어 엔지니어링을 수행해 본 경험이 많아야 합니다. 비교적 단순한 다중 스레드 응용 프로그램의 경우 BackgroundWorker 구성 요소에서 간단한 솔루션을 제공합니다. 보다 복잡한 비동기 응용 프로그램의 경우 이벤트 기반 비동기 패턴을 따르는 클래스를 구현할 수 있습니다.

이벤트 기반 비동기 패턴은 다중 스레드 응용 프로그램의 장점을 활용하면서도 다중 스레드 디자인에 내재된 여러 복잡한 문제는 피할 수 있습니다. 이 패턴을 지원하는 클래스를 사용하면 다음 작업을 수행할 수 있습니다.

  • 다운로드와 데이터베이스 작업 등 시간이 많이 걸리는 작업을 응용 프로그램을 중단하지 않고 "백그라운드에서" 수행합니다.

  • 여러 작업을 동시에 실행하며 각 작업이 완료될 때 알림을 받습니다.

  • 응용 프로그램을 중지("중단")하지 않고 리소스를 사용할 수 있을 때까지 기다립니다.

  • 익숙한 이벤트 및 대리자 모델을 사용하여 보류 중인 비동기 작업과 통신합니다. 이벤트 처리기와 대리자를 사용하는 방법에 대한 자세한 내용은 이벤트 및 대리자를 참조하십시오.

이벤트 기반 비동기 패턴을 지원하는 클래스에는 MethodNameAsync라는 메서드가 하나 이상 있습니다. 이러한 메서드는 현재 스레드에서 같은 작업을 수행하는 동기 버전을 미러링합니다. 또한 이 클래스에는 MethodNameCompleted 이벤트가 있을 수 있고 MethodNameAsyncCancel 메서드가 있거나 단순히 CancelAsync 메서드가 있을 수 있습니다.

PictureBox는 이벤트 기반 비동기 패턴을 지원하는 일반적인 구성 요소입니다. 이 구성 요소의 Load 메서드를 호출하여 이미지를 동기적으로 다운로드할 수 있지만 이미지가 너무 크거나 네트워크 연결이 느리면 다운로드 작업이 완료되고 Load 호출이 반환될 때까지 응용 프로그램이 중지("중단")됩니다.

이미지를 로드하는 동안 응용 프로그램이 계속 실행되도록 하려면 다른 이벤트를 처리할 때와 마찬가지로 LoadAsync 메서드를 호출하고 LoadCompleted 이벤트를 처리할 수 있습니다. LoadAsync 메서드를 호출하면 다운로드가 별도의 스레드 "백그라운드에서" 진행되는 동안 응용 프로그램이 계속 실행됩니다. 이미지 로드 작업이 완료되면 이벤트 처리기가 호출되고 이벤트 처리기에서 AsyncCompletedEventArgs 매개 변수를 검사하여 다운로드가 성공적으로 완료되었는지 확인할 수 있습니다.

이벤트 기반 비동기 패턴에서는 비동기 작업을 취소할 수 있어야 하며 PictureBox 컨트롤의 CancelAsync 메서드에서 이 요구 사항을 지원합니다. CancelAsync 호출하면 보류 중인 다운로드의 중지 요청이 제출되고 작업이 취소되면 LoadCompleted 이벤트가 발생합니다.

주의:

CancelAsync 요청을 할 때 마침 다운로드가 끝날 수 있으므로 Cancelled가 취소 요청을 반영하지 않을 수도 있습니다. 경합 상태라고 하는 이 문제는 다중 스레드 프로그래밍의 일반적인 문제입니다. 다중 스레드 프로그래밍의 문제에 대한 자세한 내용은 관리되는 스레딩을 구현하는 최선의 방법을 참조하십시오.

이벤트 기반 비동기 패턴 특징

이벤트 기반 비동기 패턴은 특정 클래스에서 지원되는 작업의 복잡성에 따라 몇 가지 형식이 있을 수 있습니다. 가장 단순한 클래스에는 하나의 MethodNameAsync 메서드와 이에 상응하는 MethodNameCompleted 이벤트가 있을 수 있습니다. 더 복잡한 클래스에는 여러 개의 MethodNameAsync 메서드와 각각에 상응하는 MethodNameCompleted 이벤트뿐 아니라 이 메서드의 동기 버전도 있을 수 있습니다. 클래스에서는 각 비동기 메서드의 취소, 진행률 보고 및 증분 결과를 선택적으로 지원할 수도 있습니다.

또한 비동기 메서드는 여러 개의 보류 중인 동시 호출을 지원하므로 보류 중인 다른 작업을 완료하기 전에 코드에서 보류 중인 호출을 원하는 횟수만큼 호출할 수 있습니다. 이 상황을 올바로 처리하려면 응용 프로그램이 각 작업의 완료를 추적해야 합니다.

이벤트 기반 비동기 패턴 예

SoundPlayerPictureBox 구성 요소는 이벤트 기반 비동기 패턴의 단순한 구현을 나타냅니다. WebClientBackgroundWorker 구성 요소는 이벤트 기반 비동기 패턴의 보다 복잡한 구현을 나타냅니다.

다음은 패턴을 따르는 클래스 선언의 예입니다.

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을 throw합니다.

보류 중인 작업 취소

비동기 작업은 완료되기 전에 언제라도 취소할 수 있어야 합니다. 이벤트 기반 비동기 패턴을 구현하는 클래스에는 CancelAsync 메서드(여러 비동기 메서드가 있는 경우)나 MethodNameAsyncCancel 메서드(비동기 메서드가 하나만 있는 경우)가 있습니다.

다중 호출을 허용하는 메서드에는 각 작업의 수명을 추적하는 데 사용할 수 있는 userState 매개 변수가 있으며 CancelAsync에는 보류 중인 특정 작업을 취소할 수 있는 userState 매개 변수가 있습니다.

Method1Async(string param)와 같이 한 번에 하나의 보류 상태 작업만 지원하는 메서드는 취소할 수 없습니다.

진행률 업데이트 및 증분 결과 받기

이벤트 기반 비동기 패턴을 따르는 클래스는 진행률과 증분 결과를 추적하는 이벤트를 선택적으로 제공할 수 있습니다. 이 이벤트는 일반적으로 ProgressChanged 또는 MethodNameProgressChanged로 명명되고 해당 이벤트 처리기는 ProgressChangedEventArgs 매개 변수를 사용합니다.

ProgressChanged이벤트의 이벤트 처리기는 ProgressChangedEventArgs.ProgressPercentage 속성을 검사하여 비동기 작업의 완료율을 확인합니다. 이 속성은 범위가 0에서 100까지이며 ProgressBarValue 속성을 업데이트하는 데 사용될 수 있습니다. 여러 비동기 작업이 보류 중이면 ProgressChangedEventArgs.UserState 속성을 사용하여 진행률을 보고하는 작업을 구분할 수 있습니다.

일부 클래스는 비동기 작업이 진행될 때 증분 결과를 보고할 수 있습니다. 이 결과는 ProgressChangedEventArgs에서 파생되는 클래스에 저장되고 파생된 클래스의 속성으로 표시됩니다. ProgressPercentage 속성에 액세스하는 것처럼 ProgressChanged 이벤트의 이벤트 처리기에서 이 결과를 액세스할 수 있습니다. 여러 비동기 작업이 보류 중이면 UserState 속성을 사용하여 증분 결과를 보고하는 작업을 구분할 수 있습니다.

참고 항목

작업

방법: 이벤트 기반 비동기 패턴을 지원하는 구성 요소 사용

방법: 백그라운드에서 작업 실행

방법: 백그라운드 작업을 사용하는 폼 구현

개념

최선의 이벤트 기반 비동기 패턴 구현 방법

이벤트 기반 비동기 패턴 구현 시기 결정

참조

ProgressChangedEventArgs

BackgroundWorker

AsyncCompletedEventArgs

기타 리소스

이벤트 기반 비동기 패턴을 사용한 다중 스레드 프로그래밍