Partager via


Comment : chaîner plusieurs tâches avec des continuations

Dans la bibliothèque parallèle de tâches, une tâche dont la méthode ContinueWith est appelée se nomme antécédent et la tâche définie dans la méthode ContinueWith se nomme continuation. Cet exemple indique comment utiliser les méthodes ContinueWith et ContinueWith des classes Task et Task<TResult> pour spécifier une tâche qui démarre lorsque son antécédent se termine.

L'exemple indique également comment spécifier une continuation qui s'exécute uniquement si son antécédent est annulé.

Ces exemples montrent comment continuer depuis une tâche unique. Vous pouvez également créer une continuation qui s'exécute après qu'un ou tous les groupes de tâches soient terminés ou annulés. Pour plus d'informations, consultez TaskContinueWhenAll() et TaskContinueWhenAny().

Exemple

La méthode DoSimpleContinuation montre la syntaxe de base de ContinueWith. Notez que l'antécédent est fourni comme paramètre d'entrée à l'expression lambda dans la méthode ContinueWith. Cela vous permet d'évaluer l'état de l'antécédent avant qu'il n'exécute tout travail dans la continuation. Utilisez cette surcharge simple de ContinueWith lorsque vous n'avez pas à passer un état d'une tâche à l'autre.

La méthode DoSimpleContinuationWithState indique comment utiliser ContinueWith pour passer le résultat de l'antécédent à la continuation.

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

Le paramètre de type de Task<TResult> détermine le type de retour du délégué. Cette valeur de retour est passée à la tâche de continuation. Un nombre arbitraire de tâches peut être chaîné de cette manière.

Voir aussi

Concepts

Programmation parallèle dans le .NET Framework

Expressions lambda en PLINQ et dans la bibliothèque parallèle de tâches

Autres ressources

Tâches de continuation

Parallélisme des tâches (bibliothèque parallèle de tâches)