2011-08-11 7 views
6

나는 비동기 작업을 시작한 후에 자주 취소해야하는 짧은 비동기 작업이 있습니다. "작업"클래스에는 비동기 작업이 완료까지 실행되지 않고 취소되었음을 나타내는 데 편리 할 것이라고 생각되는 IsCanceled 표시기가 있습니다. 그러나 비동기 작업을 취소 된 것으로 표시하는 유일한 방법은 말할 수 있습니다. async 함수에 TaskCanceledException을 발생시킵니다. 비정상적으로 발생하는 상황을 나타 내기 위해 일상적으로 예외를 던지면 예외를 사용해야한다는 것을 이해하는 것에 어긋납니다. 누구든지 빈번하게 발생할 것으로 예상되는 비동기 작업을 취소 할 수있는 좋은 방법을 알고 있습니까? C# async CTP - 비동기 작업을 TaskCanceledException을 throw하지 않고 취소 된 것으로 표시하려면 어떻게합니까?

class MightBeCanceled<T> 
{ 
    public readonly T Value; 
    public readonly bool IsCanceled; 

    public MightBeCanceled(T value) { Value = value; IsCanceled = false; } 
    public static MightBeCanceled<T> Canceled = new MightBeCanceled<T>(default(T), true); 
    private MightBeCanceled(T value, bool isCanceled) { Value = value; IsCanceled = isCanceled; } 
} 

... 

static async Task<MightBeCanceled<int>> Foo() 
{ 
    if (someCancellationCondition) 
     return MightBeCanceled<int>.Canceled; 
    else 
     return new MightBeCanceled<int>(42); 
} 

static async void Bar() 
{ 
    var mightBeCanceled = await Foo(); 

    if (mightBeCanceled.IsCanceled) 
     ; // Take canceled action 
    else 
     ; // Take normal action 
} 

그러나이 보인다 (나는 좋은 코딩 스타일 여기에 간결에 대한 관행을 무시했습니다) :

나의 다음-최선의 대안은 자신의 IsCanceled 숙박 시설의이 구조를 반환하는 것입니다 중복되고 사용하기가 더 어렵습니다. 그것은 IsCanceled가 2 개 (작업에 하나, MightBeCanceled에 하나) 있기 때문에 일관성 문제가 발생합니다.

+1

누가 Foo를 취소하나요? CancellationToken을 사용하여 발신자가 취소 할 수 있어야합니다. –

답변

2

문제는 기다릴 때까지 예외가 관찰되지 않는다는 것입니다. 따라서 await을 호출하면 최종 값이 반환되거나 작업이 완료 될 때까지 기다리는 시점에 결국 예외가 발생한다는 것을 의미합니다. 그러나, 당신이 신경 쓰지 않는다면 (화재와 잊기 작업 임), 그 예외는 (대부분의 경우) 별다른 문제가 아닙니다.

나도 약간 이상한 점을 발견하고, 집계 예외를 처리하기위한 작업을 항상 시도해야합니다. 그러나 조금 생각해보십시오.

try 
{ 
    var myResult = await Foo(); 

    // Do Success Actions Here... 
} 
catch(AggregateException e) 
{ 
    e.Flatten().Handle(ex => 
     { 
      if(ex is OperationCanceledException) 
      { 
       // Do Canceled Thing Here 
       return true; 
      } 

      return false; 
     }); 
} 

별로 멀지 않습니다. 여러면에서 다른 작업을 취소하고 어떻게 처리합니까? ThreadAbortException? 그것은 지금까지는 취소에 대한 특정 예외를 던지기 위해 지금까지 가져온 것 같지 않습니다.

이것은 취소 처리 방법에 대해 여러 곳에서 옹호 한 패턴과 거의 같습니다.

2

보통 취소의 목적은 비동기 작업의 호출자가 처리를 중지해야한다는 작업을 알리는 것입니다. 이를 위해 CancellationToken을 비동기 방식으로 전달합니다. 그것이 IsCancelled가 스스로를 던집니다라는 Task를 기다리는 이유입니다. 이것은 외부에서 유발 된 행동에 대한 예외적 인 신호를 의미합니다. 작업의 취소는 제어 흐름에 사용되어서는 안되며 대기중인 당사자가 더 이상 결과를 원하지 않는다는 신호를 보내면 비동기 작업에 일찍 끝내는 옵션을 제공해야합니다.

비동기 작업이 내부적으로 취소 된 경우 이미 개념에 과부하가 걸렸으며 취소의 차이를 반영하는 것이 중요하며 제안한 방법과 비슷한 결과 컨테이너의 속성이어야한다고 말하고 싶습니다. 대신 MightBeCancelled<T>이라고하는 대신 InternallyCancellableResult<T>과 같은 내용을 취소 개념의 차이를 반영하여 표현할 수 있습니다.