다음을 통해 공유


중첩된 작업 및 자식 작업

중첩된 작업은 다른 작업의 사용자 대리자 내에 만들어진 Task 인스턴스일 뿐입니다. 자식 작업은 AttachedToParent 옵션을 사용하여 만들어진 중첩된 작업입니다. 한 작업에서 자식 작업 및/또는 중첩된 작업을 필요한 만큼 만들 수 있으며 이 개수는 시스템 리소스에 의해서만 제한을 받습니다. 다음 예제에서는 간단한 중첩된 작업을 하나 만드는 부모 작업을 보여 줍니다.

Shared Sub SimpleNestedTask()
    Dim parent = Task.Factory.StartNew(Sub()
                                           Console.WriteLine("Outer task executing.")
                                           Dim child = Task.Factory.StartNew(Sub()
                                                                                 Console.WriteLine("Nested task starting.")
                                                                                 Thread.SpinWait(500000)
                                                                                 Console.WriteLine("Nested task completing.")
                                                                             End Sub)
                                       End Sub)
    parent.Wait()
    Console.WriteLine("Outer task has completed.")


End Sub

' Sample output:
'   Outer task executing.
'   Nested task starting.
'   Outer task has completed.
'   Nested task completing.
static void SimpleNestedTask()
{
    var parent = Task.Factory.StartNew(() =>
    {
        Console.WriteLine("Outer task executing.");

        var child = Task.Factory.StartNew(() =>
        {
            Console.WriteLine("Nested task starting.");
            Thread.SpinWait(500000);
            Console.WriteLine("Nested task completing.");
        });
    });

    parent.Wait();
    Console.WriteLine("Outer has completed.");
}

/* Sample output:
        Outer task executing.
        Nested task starting.
        Outer has completed.
        Nested task completing.
 */

연결된 상태의 자식 작업과 분리된 상태의 중첩된 작업 비교

자식 작업과 중첩된 작업의 가장 중요한 차이점은 중첩된 작업이 본질적으로 부모 또는 외부 작업에 독립적인 반면 연결된 자식 작업은 부모 작업과 매우 긴밀하게 동기화된다는 점입니다. 다음 예제에서와 같이 AttachedToParent 옵션을 사용하도록 작업 생성 문을 변경할 수 있습니다.

Dim child = Task.Factory.StartNew(Sub()
                                      Console.WriteLine("Attached child starting.")
                                      Thread.SpinWait(5000000)
                                      Console.WriteLine("Attached child completing.")
                                  End Sub, TaskCreationOptions.AttachedToParent)
var child = Task.Factory.StartNew((t) =>
{

    Console.WriteLine("Attached child starting.");
    Thread.SpinWait(5000000);
    Console.WriteLine("Attached child completing.");
},                TaskCreationOptions.AttachedToParent);

그러면 다음과 같은 출력이 생성됩니다.

' Parent task executing.
' Attached child starting.
' Attached child completing.
' Parent has completed.
Parent task executing.
Attached child starting.
Attached child completing.
Parent has completed.

연결된 자식 작업을 사용하여 비동기 작업의 엄격하게 동기화되는 그래프를 만들 수 있습니다. 그러나 중첩된 작업은 다른 작업과의 관계가 덜 복잡하므로 대부분의 경우 중첩된 작업을 사용하는 것이 좋습니다. 따라서 다른 작업 내에 만들어지는 작업은 기본적으로 중첩된 작업이 되며 자식 작업을 만들려면 AttachedToParent 옵션을 명시적으로 지정해야 합니다.

다음 표에서는 두 자식 작업 종류 간의 기본적인 차이점을 보여 줍니다.

범주

중첩된 작업

연결된 자식 작업

외부 작업(부모 작업)은 내부 작업이 완료될 때까지 대기함

아니요

부모 작업이 자식 작업(내부 작업)에 의해 throw된 예외를 전파함

아니요

부모 작업(외부 작업)의 상태가 자식 작업(내부 작업)의 상태에 따라 달라짐

아니요

중첩된 작업이 Task<TResult>인 분리 시나리오에서도 중첩된 작업의 Result 속성에 액세스하여 자식 작업이 완료될 때까지 부모 작업이 대기하도록 할 수 있습니다. Result 속성은 해당 작업을 완료할 때까지 차단됩니다.

Shared Sub WaitForSimpleNestedTask()
    Dim parent = Task(Of Integer).Factory.StartNew(Function()
                                                       Console.WriteLine("Outer task executing.")
                                                       Dim child = Task(Of Integer).Factory.StartNew(Function()
                                                                                                         Console.WriteLine("Nested task starting.")
                                                                                                         Thread.SpinWait(5000000)
                                                                                                         Console.WriteLine("Nested task completing.")
                                                                                                         Return 42
                                                                                                     End Function)
                                                       Return child.Result


                                                   End Function)
    Console.WriteLine("Outer has returned {0}", parent.Result)
End Sub
'Sample output:
' Outer task executing.
' Nested task starting.
' Detached task completing.
' Outer has returned 42
static void WaitForSimpleNestedTask()
{
    var outer = Task<int>.Factory.StartNew(() =>
    {
        Console.WriteLine("Outer task executing.");

        var nested = Task<int>.Factory.StartNew(() =>
        {
            Console.WriteLine("Nested task starting.");
            Thread.SpinWait(5000000);
            Console.WriteLine("Nested task completing.");
            return 42;
        });

        // Parent will wait for this detached child.
        return nested.Result;
    });

    Console.WriteLine("Outer has returned {0}.", outer.Result);
}

/* Sample output:
    Outer task executing.
    Nested task starting.
    Nested task completing.
    Outer has returned 42.
 */

중첩된 작업 및 자식 작업의 예외

중첩된 작업에서 예외를 throw하는 경우 이 예외는 중첩되지 않은 작업에서와 마찬가지로 외부 작업에서 직접 관찰되거나 처리되어야 합니다. 연결된 자식 작업에서 예외를 throw하는 경우 이 예외는 자동으로 부모 작업에 전파되고 대기 중이거나 작업의 Result 속성에 액세스하려고 하는 스레드에 다시 전파됩니다. 따라서 연결된 자식 작업을 사용하면 모든 예외를 한 지점, 즉 호출 스레드의 Wait 호출 지점에서 처리할 수 있습니다. 자세한 내용은 예외 처리(작업 병렬 라이브러리)를 참조하십시오.

취소 및 자식 작업

작업 취소는 협조적으로 이루어집니다. 따라서 "취소가 가능"하기 위해서는 연결되거나 분리된 모든 자식 작업에서 취소 토큰을 모니터링해야 합니다. 한 번의 취소 요청으로 부모 작업과 이 작업의 모든 자식 작업을 취소하려면 모든 작업에 인수와 동일한 토큰을 전달하고 각 작업에서 요청에 응답하기 위한 논리를 지정합니다. 자세한 내용은 작업 취소방법: 작업 및 해당 자식 취소를 참조하십시오.

부모 작업이 취소되는 경우

자식 작업이 시작되기 전에 부모 작업 자체가 취소되면 자식 작업(중첩된 작업)은 절대로 시작되지 않습니다. 자식 작업 또는 중첩된 작업이 이미 시작된 후에 부모 작업 자체가 취소되면 중첩된 작업(자식 작업)은 자체의 취소 논리가 있지 않은 한 정상적으로 실행 완료됩니다. 자세한 내용은 작업 취소를 참조하십시오.

중첩된 작업이 취소되는 경우

분리된 자식 작업이 해당 작업에 전달된 것과 동일한 토큰을 사용하여 취소되는 경우 부모 작업이 자식 작업에서 대기하도록 지정되어 있지 않다면 해당 예외는 있을 수 있는 협조적 취소로 처리되므로 전파되지 않습니다. 이 동작은 최상위 작업에도 동일하게 적용됩니다.

자식 작업이 취소되는 경우

연결된 자식 작업이 해당 작업에 전달된 것과 동일한 토큰을 사용하여 취소되면 AggregateException 내에서 TaskCanceledException이 조인하는 스레드에 전파됩니다. 이 경우 연결된 자식 작업의 그래프를 통해 상위로 전파되는 모든 심각한 예외뿐 아니라 심각하지 않은 예외도 처리할 수 있도록 부모 작업에서 대기해야 합니다.

자세한 내용은 예외 처리(작업 병렬 라이브러리)를 참조하십시오.

참고 항목

개념

.NET Framework의 병렬 프로그래밍

데이터 병렬 처리(작업 병렬 라이브러리)