[C# 동시성 프로그래밍] 완료한 작업 반환

참고

  • C# 동시성 프로그래밍

문제점

  • 비동기 시그니처를 사용해서 동기 메서드를 구현해야 합니다.
  • 비동기 인터페이스 또는 비동기 클래스를 상속하고 있지만 동기적으로 구현하고 싶을 때 이런 상황이 일어날 수 있습니다.
  • 이런 기법은 비동기 코드를 단위 테스트하면서 비동기 인터페이스에 사용할 간단한 스텁이나 목이 필요할 때 특히 유용합니다.

해법

  • Task.FromResult 를 사용하면 지정한 값으로 이미 완료한 Task<T> 를 새로 만들어서 반환할 수 있습니다.
interface IMyAsyncInterface
{
  Task<int> GetValueAsync();
}

class MySynchronousImplementation : IMyAsyncInterface
{
  public Task<int> GetValueAsync()
  {
    return Task.FromResult(13);
  }
}
  • 반환 값이 따로 없는 메서드라면 성공적으로 완료한 Task가 들어 있는 Task.CompletedTask를 사용할 수 있습니다.
interface IMyAsyncInterface
{
  Task DoSomethingAsync();
}

class MySynchronousImplementation : IMyAsyncInterface
{
  public Task DoSomethingAsync()
  {
    return Task.CompletedTask;
  }
}
  • Task.FromResult는 성공적인 결과로 완료한 작업만 제공합니다.
  • NotImplementedException 으로 완료한 작업 등 결과가 다른 작업이 필요하면 Task.FromException 을 사용할 수 있습니다.
Task<T> NotImplementedAsync<T>()
{
  return Task.FromException<T>(new NotImplementedException());
}
  • 마찬가지로 전달한 CancellationToken 으로 이미 취소한 작업을 생성하는 Task.FromCanceled 도 있습니다.
Task<int> GetValueAsync(CancellationToken cancellationToken)
{
  if(cancellationToken.IsCancellationRequested)
    return Task.FromCanceled<int>(cancellationToekn);
  return Task.FromResult(13)
}
  • 동기적 구현이 실패할 가능성이 있다면 다음과 같이 예외를 잡은 뒤에 Task.FromException을 사용해서 반환해야 합니다.
interface IMyAsyncInterface
{
  Task DoSomethingAsync();
}

class MySynchronousImplementation : IMyAsyncInterface
{
  public Task DoSomethingAsync()
  {
    try
    {
        DoSomethingSynchronously();
        return Task.CompletedTask;
    }
    catch(Exception ex)
    {
        return Task.FromException(ex);
    }
  }
}

정리

  • 동기적인 코드를 사용해서 비동기 인터페이스를 구현하려면 모든 형태의 차단을 피애햐 합니다.
  • 비동기적으로 구현할 수 있는데도 다른 작업을 차단하고 자기 작업을 완료한 뒤에 반환한다면 비동기 메서드로 이상적이지 않습니다.
  • 주기적으로 같은 값을 사용해서 Task.FromResult로 작업을 만들어야 한다면 작업을 미리 만들어서 저장해 놓는 방법도 고려하길 바랍니다.
  • 예를 들어 다음과 같이 결과값 0으로 Task 를 만들어 놓으면 가비지 컬렉션으로 사라질 인스턴스를 다시 만들지 않아도 항상 같은 작업 결과를 사용할 수 있습니다.
private static readonly Task<int> zeroTask = Task.FromResult(0);
Task<int> GetValueAsync()
{
  return zeroTask;
}
  • Task.FromResult, Task.FromException, Task.FromCanceled 는 모두 범용 형식인 TaskCompletionSource<T> 의 헬퍼 메서드이자 축약형 입니다.
  • TaskCompletionSource<T> 는 다른 방식의 비동기 코드와 상호 운용에 유용한 하위 레벨 형식입니다.
  • 일반적으로 이미 완료한 작업을 반환하고 싶으면 축약형인 Task.FromResult 등을 사용해야 합니다.
728x90

이 글을 공유하기

댓글

Designed by JB FACTORY