다음을 통해 공유


이벤트 기반 비동기 패턴 구현에 대한 모범 사례

이벤트 기반 비동기 패턴은 친숙한 이벤트 및 대리자 의미 체계를 사용하여 클래스에서 비동기 동작을 노출하는 효과적인 방법을 제공합니다. 이벤트 기반 비동기 패턴을 구현하려면 몇 가지 특정 동작 요구 사항을 따라야 합니다. 다음 섹션에서는 이벤트 기반 비동기 패턴을 따르는 클래스를 구현할 때 고려해야 할 요구 사항 및 지침을 설명합니다.

개요는 이벤트 기반 비동기 패턴 구현을 참조하세요.

필수 행동 보장

이벤트 기반 비동기 패턴을 구현하는 경우 클래스가 제대로 동작하고 클래스의 클라이언트가 이러한 동작에 의존할 수 있도록 여러 가지 보장을 제공해야 합니다.

완료

성공적으로 완료, 오류 또는 취소가 있는 경우 항상 MethodNameCompleted 이벤트 처리기를 호출합니다. 애플리케이션은 유휴 상태로 유지되고 완료가 발생하지 않는 상황이 발생하지 않아야 합니다. 이 규칙의 한 가지 예외는 비동기 작업 자체가 완료되지 않도록 설계된 경우입니다.

Completed 이벤트 및 EventArgs

각 개별 MethodNameAsync 메서드에 대해 다음 디자인 요구 사항을 적용합니다.

  • 메서드와 동일한 클래스에서 MethodNameCompleted 이벤트를 정의합니다.

  • EventArgs 클래스에서 파생되는 MethodNameCompleted 이벤트를 위한 클래스 및 관련 위임자를 정의합니다. 기본 클래스 이름은 MethodNameCompletedEventArgs 형식이어야 합니다.

  • 클래스가 EventArgsMethodName 메서드의 반환 값과 관련이 있는지 확인합니다. 클래스를 EventArgs 사용하는 경우 개발자가 결과를 캐스팅할 필요가 없습니다.

    다음 코드 예제에서는 이 디자인 요구 사항의 양호한 구현과 잘못된 구현을 각각 보여줍니다.

// Good design
private void Form1_MethodNameCompleted(object sender, xxxCompletedEventArgs e)
{
    DemoType result = e.Result;
}

// Bad design
private void Form1_MethodNameCompleted(object sender, MethodNameCompletedEventArgs e)
{
    DemoType result = (DemoType)(e.Result);
}
  • EventArgs을 반환하는 메서드를 위한 void 클래스를 정의하지 마세요. 대신 클래스의 인스턴스를 AsyncCompletedEventArgs 사용합니다.

  • 항상 MethodNameCompleted 이벤트를 발생시키는지 확인합니다. 이 이벤트는 성공적인 완료, 오류 또는 취소 시 발생해야 합니다. 애플리케이션은 유휴 상태로 유지되고 완료가 발생하지 않는 상황이 발생하지 않아야 합니다.

  • 비동기 작업에서 발생하는 예외를 catch하고 catch된 예외를 속성에 Error 할당해야 합니다.

  • 작업을 완료하는 동안 오류가 발생한 경우 결과에 액세스할 수 없습니다. Error 속성이 null이 아닐 때, EventArgs 구조체의 어떤 속성에 접근하려고 하면 예외가 발생하도록 하십시오. 이 RaiseExceptionIfNecessary 확인을 수행하려면 이 메서드를 사용합니다.

  • 시간 초과를 오류로 모델링합니다. 제한 시간이 발생하면 MethodNameCompleted 이벤트를 발생시키고 TimeoutException 속성에 Error를 할당합니다.

  • 클래스가 여러 동시 호출을 지원하는 경우 MethodNameCompleted 이벤트에 적절한 userSuppliedState 개체가 포함되어 있는지 확인합니다.

  • 적절한 스레드 및 애플리케이션 수명 주기에서 적절한 시간에 MethodNameCompleted 이벤트가 발생하는지 확인합니다. 자세한 내용은 스레딩 및 컨텍스트 섹션을 참조하세요.

동시에 작업 실행

  • 클래스가 여러 동시 호출을 지원하는 경우 개체 반환 상태 매개 변수 또는 작업 ID를 사용하는 MethodNameuserSuppliedState 오버로드를 정의하여 개발자가 각 호출을 개별적으로 추적할 수 있습니다. 이 매개 변수는 항상 MethodNameAsync 메서드 시그니처의 마지막 매개 변수여야 합니다.

  • 클래스가 개체 반환 상태 매개 변수 또는 작업 ID를 사용하는 MethodNameAsync 오버로드를 정의하는 경우 해당 작업 ID를 사용하여 작업의 수명을 추적하고 완료 처리기에 다시 제공해야 합니다. 도우미 클래스가 사용 가능합니다. 동시성 관리에 대한 자세한 내용은 방법: 이벤트 기반 비동기 패턴을 지원하는 구성 요소 구현을 참조하세요.

  • 클래스가 상태 매개 변수 없이 MethodNameAsync 메서드를 정의하고 여러 동시 호출을 지원하지 않는 경우, 이전 MethodNameAsync 호출이 완료되기 전에 MethodNameAsync를 호출하려고 시도하면 오류가 발생하도록 합니다InvalidOperationException.

  • 일반적으로 매개 변수가 없는 MethodNameAsync 메서드 userSuppliedState 가 여러 번 호출되어 처리 중인 작업이 여러 번 있는 경우 예외를 발생시키지 마세요. 클래스가 해당 상황을 명시적으로 처리할 수 없는 경우 예외를 발생하지만 개발자가 이러한 여러 구별할 수 없는 콜백을 처리할 수 있다고 가정합니다.

결과 확인

진행률 보고

  • 가능한 경우 진행률 보고를 지원합니다. 이를 통해 개발자는 클래스를 사용할 때 더 나은 애플리케이션 사용자 환경을 제공할 수 있습니다.

  • ProgressChanged 또는 MethodNameProgressChanged 이벤트를 구현하는 경우 해당 작업의 MethodNameCompleted 이벤트가 발생한 후 특정 비동기 작업에 대해 발생하는 이벤트가 없는지 확인합니다.

  • 표준 ProgressChangedEventArgs 이 채워지는 경우, ProgressPercentage이 항상 백분율로 해석될 수 있는지 확인합니다. 백분율은 정확할 필요는 없지만 백분율을 나타내야 합니다. 진행률 보고 측정 기준이 백분율 이외의 항목이어야 하는 경우, ProgressChangedEventArgs 클래스에서 파생된 클래스를 만들고 ProgressPercentage를 0으로 둡니다. 백분율 이외의 보고 메트릭을 사용하지 않습니다.

  • ProgressChanged 적절한 스레드 및 애플리케이션 수명 주기에서 적절한 시간에 이벤트가 발생했는지 확인합니다. 자세한 내용은 스레딩 및 컨텍스트 섹션을 참조하세요.

IsBusy 구현

  • 클래스가 IsBusy 여러 동시 호출을 지원하는 경우 속성을 노출하지 마세요. 예를 들어 XML 웹 서비스 프록시는 비동기 메서드의 여러 동시 호출을 지원하므로 속성을 노출 IsBusy 하지 않습니다.

  • 이 속성은 IsBusytrueAsync 메서드가 호출된 후 및 MethodNameCompleted 이벤트가 발생하기 전에 반환 되어야 합니다. 그렇지 않으면 false을 반환해야 합니다. BackgroundWorkerWebClient 구성 요소는 속성을 노출하는 클래스의 예입니다IsBusy.

취소

  • 가능한 경우 취소를 지원합니다. 이를 통해 개발자는 클래스를 사용할 때 더 나은 애플리케이션 사용자 환경을 제공할 수 있습니다.

  • 취소의 경우 Cancelled 개체에 AsyncCompletedEventArgs 플래그를 설정합니다.

  • 결과에 액세스하려고 하면 작업이 취소되었다는 내용을 나타내는 InvalidOperationException가 발생하도록 확인합니다. 이 AsyncCompletedEventArgs.RaiseExceptionIfNecessary 확인을 수행하려면 이 메서드를 사용합니다.

  • 취소 메서드에 대한 호출이 항상 성공적으로 반환되고 예외가 발생하지 않도록 합니다. 일반적으로 클라이언트는 지정된 시간에 작업을 진정으로 취소할 수 있는지 여부를 알리지 않으며 이전에 발급한 취소가 성공했는지 여부에 대한 알림을 받습니다. 그러나 애플리케이션이 완료 상태에 참여하기 때문에 취소가 성공하면 애플리케이션에 항상 알림이 제공됩니다.

  • 작업이 취소되면 MethodNameCompleted 이벤트를 트리거합니다.

오류 및 예외

스레딩 및 컨텍스트

클래스의 올바른 작업을 위해 클라이언트의 이벤트 처리기는 ASP.NET 및 Windows Forms 애플리케이션을 포함하여 지정된 애플리케이션 모델에 대한 적절한 스레드 또는 컨텍스트에서 호출되어야 합니다. 비동기 클래스가 애플리케이션 모델 AsyncOperationAsyncOperationManager에서 올바르게 동작하는지 확인하기 위해 두 가지 중요한 도우미 클래스가 제공됩니다.

AsyncOperationManager는 하나의 메서드 CreateOperation를 제공하며, 이는 AsyncOperation을 반환합니다. MethodNameAsync 메서드는 CreateOperation을(를) 호출하며, 클래스는 반환된 AsyncOperation을(를) 사용하여 비동기 작업의 수명을 추적합니다.

진행률, 증분 결과 및 완료를 클라이언트에게 보고하려면, Post에서 OperationCompletedAsyncOperation 메서드를 호출하십시오. AsyncOperation 는 클라이언트의 이벤트 처리기에 대한 호출을 적절한 스레드 또는 컨텍스트로 마샬링하는 작업을 담당합니다.

비고

애플리케이션 모델의 정책에 대해 명시적으로 반대하지만 이벤트 기반 비동기 패턴을 사용할 때의 다른 이점을 활용하려는 경우 이러한 규칙을 우회할 수 있습니다. 예를 들어 Windows Forms에서 작동하는 클래스를 스레드 해제할 수 있습니다. 개발자가 암시적 제한을 이해하는 한 무료 스레드 클래스를 만들 수 있습니다. 콘솔 애플리케이션은 Post 호출의 실행을 동기화하지 않습니다. 이로 인해 ProgressChanged 이벤트가 순서대로 발생하지 않을 수 있습니다. 호출을 직렬 실행하려면 Post, System.Threading.SynchronizationContext 클래스를 구현하고 설치합니다.

비동기 작업을 사용하고 AsyncOperationAsyncOperationManager 사용하도록 설정하는 방법에 대한 자세한 내용은 방법: 이벤트 기반 비동기 패턴을 지원하는 구성 요소 구현을 참조하세요.

지침

  • 이상적으로 각 메서드 호출은 다른 호출과 독립적이어야 합니다. 호출을 공유 리소스와 결합하지 않아야 합니다. 호출 간에 리소스를 공유해야 하는 경우 구현에 적절한 동기화 메커니즘을 제공해야 합니다.

  • 클라이언트가 동기화를 구현해야 하는 디자인은 권장되지 않습니다. 예를 들어 전역 정적 개체를 매개 변수로 수신하는 비동기 메서드를 사용할 수 있습니다. 이러한 메서드를 동시에 여러 개 호출하면 데이터가 손상되거나 교착 상태가 발생할 수 있습니다.

  • 서명에서 다중 호출 오버로드를userState 사용하여 메서드를 구현하는 경우 클래스는 사용자 상태 또는 작업 ID 및 해당 보류 중인 작업의 컬렉션을 관리해야 합니다. 다양한 호출이 lock 개체를 컬렉션에 추가하고 제거하므로, 이 컬렉션은 userState 영역으로 보호되어야 합니다.

  • 가능하고 적절한 경우 클래스를 CompletedEventArgs 다시 사용하는 것이 좋습니다. 이 경우 지정된 대리자와 형식이 단일 메서드에 연결되지 않으므로 명명이 메서드 이름과 EventArgs 일치하지 않습니다. 그러나 개발자가 속성 EventArgs 에서 검색된 값을 캐스팅하도록 강제하는 것은 허용되지 않습니다.

  • 파생 Component클래스를 작성하는 경우 고유한 SynchronizationContext 클래스를 구현하고 설치하지 마세요. 애플리케이션 모델이 구성 요소가 아닌, 사용되는 SynchronizationContext를 제어합니다.

  • 모든 종류의 다중 스레딩을 사용하는 경우 매우 심각하고 복잡한 버그에 노출될 수 있습니다. 다중 스레딩을 사용하는 솔루션을 구현하기 전에 관리되는 스레딩 모범 사례를 참조하세요.

참고하십시오