方法: 複数のタスクを継続に連結する

タスク並列ライブラリでは、ContinueWith メソッドが呼び出されるタスクは継続元タスクと呼ばれ、ContinueWith メソッドで定義されているタスクは継続と呼ばれます。 この例では、Task クラスおよび Task<TResult> クラスの ContinueWith メソッドと ContinueWith メソッドを使用して、継続元タスクが終了した後に開始されるタスクを指定する方法を示します。

この例では、継続元タスクが取り消された場合にのみ実行される継続を指定する方法も示します。

これらの例では、単一のタスクから続行する方法を示します。 タスクのグループの一部またはすべてが完了したり、取り消されたりした後に実行する継続を作成することもできます。 詳細については、「Task.WhenAll」および「Task.WhenAny」を参照してください。

使用例

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> の型パラメーターによって、デリゲートの戻り値の型が判別されます。 この戻り値は、継続タスクに渡されます。 同様の方法で、任意の数のタスクを連結できます。

参照

概念

継続タスク

PLINQ および TPL のラムダ式

その他の技術情報

.NET Framework の並列プログラミング

タスクの並列化 (タスク並列ライブラリ)