[C# 동시성 프로그래밍] - 일정 시간 동안 일시 정지

참고

  • C# 동시성 프로그래밍

문제점

  • 비동기적으로 일정 시간을 기야려야 합니다.
  • 단위 테스트 또는 재시도 지연을 구현할 때 흔한 상황입니다.
  • 간단한 타임아웃을 코딩할 때 필요하기도 합니다.

해법

  • Task 형식에 들어 있는 정적 메서드 Delay는 지정한 시간 뒤에 완료하는 작업을 반환합니다.
  • 다음 예제는 비동기적으로 완료하는 작업을 정의합니다.
  • 비동기 작업의 구색을 갖추려면 동기적 성공, 비동기적 성공은 물론 비동기적 실패도 시험해야 합니다.
  • 다음 예제는 비동기적 성공 사례에 쓰이는 작업을 반환합니다.
async Task<T> DelayResult<T>(T result, TimeSpan delay)
{
  await Task.Delay(delay);
  return result;
}
  • 지수 백오프는 재시도 사이의 지연 시간을 점점 늘리는 전략으로 웹 서비스 관련 작업에 사용하면 서버가 재시도로 넘치지 않게 막을 수 있습니다.
  • 다음 예제는 지수 백오프의 간단한 구현입니다.
async Task<string> DownloadStringWithRetries(HttpClient client, string uri)
{
  // 1초 후, 다음에는 2호 후, 그 다음에는 4초 후, 이런식으로 재시도
  TimeSpan nextDelay = TimeSpan.FromSeconds(1);

  for(int i = 0; i != 3; ++i)
  {
    try
    {
      return await client.GetStringAsync(uri)
    }
    catch
    {

    }

    await Task.Delay(nextDelay);
    nextDelay = nextDelay + nextDelay;
  }

  return await client.GetStringAsync(uri);
}

실제 제품이라면, Polly NuGet 라이브러리를 사용하는 것을 추천합니다.


  • 또한 Task.Delay는 간단한 타임아웃으로도 쓸 수 있습니다.
  • CancallationTokenSource는 타임아웃 구현에 쓰이는 일반적인 형식입니다.
  • 무한히 대기하는 Task.Delay 안에 취소 토큰을 넣으면 정해진 시간 뒤에 취소할 타임아웃 작업을 만들 수 있습니다.
async Task<string> DownloadStringWithTimeout(HttpClient client, string uri)
{
  using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(3));
  Task<string> downloadTask = client.GetStringAsync(uri);
  Task timeoutTask = Task.Delay(Timeout.InfiniteTimeSpan, cts.Token);

  Task completedTask = await Task.WhenAny(downloadTask, timeoutTask);
  if(completedTask == timeoutTask)
    return null;
  return await downloadTask;
}
  • Task.Delay를 소프트 타임아웃으로 쓸 수는 있지만 한계가 있습니다.
  • 타임아웃을 넘겨도 작업을 취소하지 않기 때문에 앞의 예제에서 다운로드 작업은 다운로드를 계속하며 따로 작업을 삭제하지 않으면 모든 응답을 다운로드 합니다.
  • 더 좋은 방법은 취소 토큰을 타임아웃으로 사용해서 예제의 GetStringAsync와 같은 작업에 직접 전달하는 것 입니다.
  • 즉 취소할 수 없는 작업이 있으면 다른 코드에서 Task.Delay를 사용해서 원래 작업의 타임아웃처럼 사용할 수 있습니다.

결론

  • Task.Delay는 비동기 코드의 단위 테스트 또는 재시도 로직 구현에 좋은 선택입니다.
  • 하지만, 타임아웃 구현에는 CancellationToekn 사용을 권장합니다.
728x90

이 글을 공유하기

댓글

Designed by JB FACTORY