방프리

24.03.10 Chapter3. 태스크 기반 비동기 프로그래밍 (Item 32) 본문

C#/More Effective C#

24.03.10 Chapter3. 태스크 기반 비동기 프로그래밍 (Item 32)

방프리 2024. 3. 10. 22:48

Item 32 : 비동기 작업은 태스크 객체를 사용해 구성하라

태스크란 다른 리소스에 작업을 위임할 수 있도록 추상화한 개념이다. 태스크는 자기의 작업이 완료될 때 Task 객체를 반환하는데 이를 반복문에 사용하거나 여러 태스크를 처리하는 로직을 사용했을 때 대기를 해야하는 경우가 있다.

특히 Task.WhenAny()는 호출할 때마다 새로운 태스크를 생성하기에 TaskCompletionSource를 통해 관리를 할 수 있다.

public static Task<T>[] OrderByCompletion<T>(
    this IEnuemerable<Task<T>> tasks)
{
    var sourceTask = tasks.ToList();
    
    var completionSources = 
        new TaskCompletionSource<T>[sourceTasks.Count];
    var outputTasks = new Task<T>[completionSources.Length];
    for (int i = 0; i < completionSources.Length; ++i)
    {
        completionSources[i] = new TaskCompletionSource<T>();
        outputTasks[i] = completionSources[i].Task;
    }
    
    int nextTaskIndex = -1;
    Action<Task<T>> continuation = completed =>
    {
        var bucket = completionSources
            [Interlocked.Increment(ref nextTaskIndex)];
        if (completed.IsCompleted)
            bucket.TrySetResult(completed.Result);
        else if (completed.IsFaulted)
            bucket.TrySetException(completed.Exception);
    };
    
    foreach (var inputTask in sourceTasks)
    {
        inputTask.ContinueWith(continuation,
            CancellationToken.None,
            TaskContinuationoptions.ExecuteSynchronously,
            TaskScheduler.Default);
    }
    
    return outputTasks;
}

태스크의 각자 결과를 TaskCompletionSource의 자기 위치 인덱스에 배치한다.

Comments