Gewusst wie: Verketten von mehreren Aufgaben mit Fortsetzungen

In der Task Parallel Library wird eine Aufgabe, deren ContinueWith-Methode aufgerufen wird, als Vorgängeraufgabe bezeichnet, während eine Aufgabe, die in der ContinueWith-Methode definiert wird, als Fortsetzung bezeichnet wird. In diesem Beispiel wird gezeigt, wie Sie mit der ContinueWith-Methode und der ContinueWith-Methode der Task-Klasse und der Task<TResult>-Klasse eine Aufgabe angeben, die nach Abschluss der Vorgängeraufgabe gestartet wird.

Darüber hinaus wird in dem Beispiel gezeigt, wie Sie eine Fortsetzung angeben, die nur ausgeführt wird, wenn deren Vorgänger abgebrochen wurde.

In diesen Beispielen wird die Fortsetzung einer einzelnen Aufgabe veranschaulicht. Sie können auch eine Fortsetzung erstellen, die nach dem Abschluss bzw. Abbruch einer bestimmten oder aller Aufgaben in einer Gruppe ausgeführt wird. Weitere Informationen finden Sie unter TaskContinueWhenAll() und TaskContinueWhenAny().

Beispiel

Die DoSimpleContinuation-Methode zeigt die grundlegende Syntax für ContinueWith. Beachten Sie, dass die Vorgängeraufgabe als Eingabeparameter für den Lambda-Ausdruck in der ContinueWith-Methode bereitgestellt wird. Sie können so den Status der Vorgängeraufgabe auswerten, bevor diese Vorgänge in der Fortsetzung ausführt. Verwenden Sie diese einfache Überladung von ContinueWith, wenn Sie keinen Zustand von einer Aufgabe an eine andere übergeben müssen.

Die DoSimpleContinuationWithState-Methode zeigt, wie Sie mit ContinueWith das Ergebnis von der Vorgängeraufgabe an die Fortsetzungsaufgabe übergeben.

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));
        }
    }
}

Der Typparameter von Task<TResult> bestimmt den Rückgabetyp des Delegaten. Dieser Rückgabewert wird an die Fortsetzungsaufgabe übergeben. Auf diese Weise kann eine beliebige Anzahl von Aufgaben verkettet werden.

Siehe auch

Konzepte

Parallele Programmierung in .NET Framework

Lambda-Ausdrücke in PLINQ und TPL

Weitere Ressourcen

Fortsetzungsaufgaben

Aufgabenparallelität (Task Parallel Library)