방법: 연속 작업을 사용하여 여러 작업 연결

작업 병렬 라이브러리에서 ContinueWith 메서드가 호출된 작업은 선행 작업이라고 하며 ContinueWith 메서드에 정의된 작업은 연속 작업이라고 합니다. 이 예제에서는 TaskTask<TResult> 클래스의 ContinueWithContinueWith 메서드를 사용하여 선행 작업이 완료된 후 시작되는 작업을 지정하는 방법을 보여 줍니다.

또한 이 예제에서는 선행 작업이 취소된 경우에만 실행되는 연속 작업을 지정하는 방법도 보여 줍니다.

예제를 통해 단일 작업에서 연속으로 작업을 수행하는 방법을 알아볼 수 있습니다. 일련의 작업 중 일부 또는 모두가 완료되거나 취소된 후에 실행되는 연속 작업을 만들 수도 있습니다. 자세한 내용은 TaskContinueWhenAll() 및 TaskContinueWhenAny()를 참조하십시오.

예제

DoSimpleContinuation 메서드는 ContinueWith의 기본 구문을 보여 줍니다. ContinueWith 메서드의 람다 식에는 선행 작업이 입력 매개 변수로 제공되어 있습니다. 이렇게 하면 연속 작업에서 작업을 수행하기 전에 선행 작업의 상태를 확인할 수 있습니다. 한 작업에서 다른 작업으로 상태를 전달할 필요가 없는 경우에는 ContinueWith의 이 간단한 오버로드를 사용합니다.

DoSimpleContinuationWithState 메서드는 ContinueWith를 사용하여 선행 작업의 결과를 연속 작업에 전달하는 방법을 보여 줍니다.

Imports System.IO
Imports System.Threading
Imports System.Threading.Tasks
Module ContinueWith

    Sub Main()
        DoSimpleContinuation()

        Console.WriteLine("Press any key to exit")
        Console.ReadKey()
    End Sub


    Sub DoSimpleContinuation()
        Dim path As String = "C:\users\public\TPLTestFolder\"
        Try
            Dim firstTask = New Task(Sub() CopyDataIntoTempFolder(path))
            Dim secondTask = firstTask.ContinueWith(Sub(t) CreateSummaryFile(path))
            firstTask.Start()
        Catch e As AggregateException
            Console.WriteLine(e.Message)
        End Try
    End Sub

    ' A toy function to simulate a workload
    Sub CopyDataIntoTempFolder(ByVal path__1 As String)
        System.IO.Directory.CreateDirectory(path__1)
        Dim rand As New Random()
        For x As Integer = 0 To 49
            Dim bytes As Byte() = New Byte(999) {}
            rand.NextBytes(bytes)
            Dim filename As String = Path.GetRandomFileName()
            Dim filepath As String = Path.Combine(path__1, filename)
            System.IO.File.WriteAllBytes(filepath, bytes)
        Next
    End Sub

    Sub CreateSummaryFile(ByVal path__1 As String)
        Dim files As String() = System.IO.Directory.GetFiles(path__1)
        Parallel.ForEach(files, Sub(file)
                                    Thread.SpinWait(5000)
                                End Sub)

        System.IO.File.WriteAllText(Path.Combine(path__1, "__SummaryFile.txt"), "did my work")
        Console.WriteLine("Done with task2")
    End Sub

    Sub DoSimpleContinuationWithState()
        Dim nums As Integer() = {19, 17, 21, 4, 13, 8, _
        12, 7, 3, 5}
        Dim f0 = New Task(Of Double)(Function() nums.Average())
        Dim f1 = f0.ContinueWith(Function(t) GetStandardDeviation(nums, t.Result))

        f0.Start()
        Console.WriteLine("the standard deviation is {0}", f1)
    End Sub

    Function GetStandardDeviation(ByVal values As Integer(), ByVal mean As Double) As Double
        Dim d As Double = 0.0R
        For Each n In values
            d += Math.Pow(mean - n, 2)
        Next
        Return Math.Sqrt(d / (values.Length - 1))
    End Function
End Module
using System;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace ContinueWith
{
    class Continuations
    {
        static void Main()
        {
            SimpleContinuation();            

            Console.WriteLine("Press any key to exit");
            Console.ReadKey();
        }

        static void SimpleContinuation()
        {
            string path = @"C:\users\public\TPLTestFolder\";
            try
            {
                var firstTask = new Task(() => CopyDataIntoTempFolder(path));
                var secondTask = firstTask.ContinueWith((t) => CreateSummaryFile(path));
                firstTask.Start();
            }
            catch (AggregateException e)
            {
                Console.WriteLine(e.Message);
            }
        }

        // A toy function to simulate a workload
        static void CopyDataIntoTempFolder(string path)
        {
            System.IO.Directory.CreateDirectory(path);
            Random rand = new Random();
            for (int x = 0; x < 50; x++)
            {
                byte[] bytes = new byte[1000];
                rand.NextBytes(bytes);
                string filename = Path.GetRandomFileName();
                string filepath = Path.Combine(path, filename);
                System.IO.File.WriteAllBytes(filepath, bytes);
            }
        }

        static void CreateSummaryFile(string path)
        {
            string[] files = System.IO.Directory.GetFiles(path);
            Parallel.ForEach(files, (file) =>
                {
                    Thread.SpinWait(5000);
                });

            System.IO.File.WriteAllText(Path.Combine(path, "__SummaryFile.txt"), "did my work");
            Console.WriteLine("Done with task2");
        }

        static void SimpleContinuationWithState()
        {
            int[] nums = { 19, 17, 21, 4, 13, 8, 12, 7, 3, 5 };
            var f0 = new Task<double>(() =>  nums.Average());
            var f1 = f0.ContinueWith( t => GetStandardDeviation(nums, t.Result));

            f0.Start();
            Console.WriteLine("the standard deviation is {0}", f1.Result);          
        }        

        private static double GetStandardDeviation(int[] values, double mean)
        {
            double d = 0.0;
            foreach (var n in values)
            {
                d += Math.Pow(mean - n, 2);
            }
            return Math.Sqrt(d / (values.Length - 1));
        }
    }
}

Task<TResult>의 형식 매개 변수는 대리자의 반환 형식을 결정하며 이 반환 값이 연속 작업에 전달됩니다. 이와 같은 방법으로 여러 작업을 개수에 관계없이 체인할 수 있습니다.

참고 항목

개념

.NET Framework의 병렬 프로그래밍

PLINQ 및 TPL의 람다 식

기타 리소스

연속 작업

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