내용 보기

작성자

관리자 (IP : 106.247.248.10)

날짜

2023-04-11 09:20

제목

[C#] [스크랩] Task<T>에 유용한 5가지 확장 | Steven Giesel


이 짧은 블로그 게시물에서는 .NET Task의 유용한 5가지 확장 메서드를 보여드리겠습니다. 확장 메서드로 빌드할 것이므로 사용하기 쉽습니다. 그 위에 사용 방법에 대한 작은 예를 보여 드리겠습니다. 그럼 시작해 봅시다!

1. 발생하고 잊어버리기

때로는 작업을 실행하고 잊어버리고 싶을 때가 있습니다. 즉, 작업을 시작하고 싶지만 완료될 때까지 기다리기 싫을 때가 있습니다. 이 기능은 작업을 시작하고 싶지만 결과에 신경 쓰지 않을 때(중요하지 않은 작업) 유용합니다. 예를 들어 이메일을 보내는 작업을 시작하려는 경우입니다. 이메일이 전송될 때까지 기다렸다가 코드를 계속하고 싶지는 않을 것입니다. 따라서 FireAndForget 확장 메서드를 사용하여 작업을 시작하고 잊어버릴 수 있습니다. 선택적으로 메서드에 오류 처리기를 전달할 수 있습니다. 이 오류 처리기는 작업에서 예외가 발생할 때 호출됩니다.

public static void FireAndForget(
  this Task task,
  Action<Exception> errorHandler = null)
{
    task.ContinueWith(t =>
    {
        if (t.IsFaulted && errorHandler != null)
            errorHandler(t.Exception);
    }, TaskContinuationOptions.OnlyOnFaulted);
}

사용:

SendEmailAsync().FireAndForget(errorHandler => Console.WriteLine(errorHandler.Message));

2. 재시도

특정 횟수만큼 작업을 재시도하려면 Retry 확장 메서드를 사용할 수 있습니다. 이 방법은 작업이 성공하거나 최대 재시도 횟수에 도달할 때까지 작업을 재시도합니다. 재시도 사이에 지연 시간을 전달할 수 있습니다. 이 지연은 각 재시도 사이에 사용됩니다.

public static async Task<TResult> Retry<TResult>(this Func<Task<TResult>> taskFactory, int maxRetries, TimeSpan delay)
{
    for (int i = 0; i < maxRetries; i++)
    {
        try
        {
            return await taskFactory().ConfigureAwait(false);
        }
        catch
        {
            if (i == maxRetries - 1)
                throw;
            await Task.Delay(delay).ConfigureAwait(false);
        }
    }

    return default(TResult); // Should not be reached
}

사용:

var result = await (() => GetResultAsync()).Retry(3, TimeSpan.FromSeconds(1));

3. OnFailure

태스크에서 예외가 발생하면 콜백 함수를 실행합니다.

public static async Task OnFailure(this Task task, Action<Exception> onFailure)
{
    try
    {
        await task.ConfigureAwait(false);
    }
    catch (Exception ex)
    {
        onFailure(ex);
    }
}

사용:

await GetResultAsync().OnFailure(ex => Console.WriteLine(ex.Message));

4. 타임아웃

작업에 시간 제한을 설정하고 싶을 때가 있습니다. 이 기능은 작업이 너무 오래 실행되는 것을 방지하려는 경우에 유용합니다. Timeout 확장 메서드를 사용하여 작업의 시간 제한을 설정할 수 있습니다. 작업이 시간 제한보다 오래 걸리면 작업이 취소됩니다.

public static async Task WithTimeout(this Task task, TimeSpan timeout)
{
    var delayTask = Task.Delay(timeout);
    var completedTask = await Task.WhenAny(task, delayTask);
    if (completedTask == delayTask)
        throw new TimeoutException();

    await task;
}

사용:

await GetResultAsync().WithTimeout(TimeSpan.FromSeconds(1));

대체

작업이 실패할 때 대체 값을 사용하려는 경우가 있습니다. Fallback 확장 메서드를 사용하여 작업 실패 시 폴백 값을 사용할 수 있습니다.

public static async Task<TResult> Fallback<TResult>(this Task<TResult> task, TResult fallbackValue)
{
    try
    {
        return await task.ConfigureAwait(false);
    }
    catch
    {
        return fallbackValue;
    }
}

사용:

var result = await GetResultAsync().Fallback("fallback");

결론

여기까지입니다. Task의 5가지 유용한 확장입니다 . 물론 원하신다면 ValueTask으로도 사용할 수 있습니다. 더 필요하신 것이 있으시면 알려주세요!


출처1

https://forum.dotnetdev.kr/t/net-task-t-5-steven-giesel/6778

출처2

https://steven-giesel.com/blogPost/d38e70b4-6f36-41ff-8011-b0b0d1f54f6e