タスク ベースの非同期プログラミングTask-based asynchronous programming

タスク並列ライブラリ (TPL) は、非同期操作を表すタスクの概念に基づいています。The Task Parallel Library (TPL) is based on the concept of a task, which represents an asynchronous operation. いくつかの点で、タスクはスレッドまたは ThreadPool 作業項目に似ていますが、高いレベルで抽象化しています。In some ways, a task resembles a thread or ThreadPool work item, but at a higher level of abstraction. タスクの並列化とは、1 つ以上の独立したタスクを同時に実行することです。The term task parallelism refers to one or more independent tasks running concurrently. タスクが提供する主な利点は次の 2 つです。Tasks provide two primary benefits:

  • システム リソースをより効率的かつスケーラブルに利用する。More efficient and more scalable use of system resources.

    背後では、タスクは ThreadPool へのキューとして配置されます。これはスレッド数を判別および調整し、負荷分散によってスループットを最大化する、アルゴリズムを使用して強化されています。Behind the scenes, tasks are queued to the ThreadPool, which has been enhanced with algorithms that determine and adjust to the number of threads and that provide load balancing to maximize throughput. これによりタスクが比較的軽量化されるため、多数のタスクを作成して粒度の高い並列化を実現できます。This makes tasks relatively lightweight, and you can create many of them to enable fine-grained parallelism.

  • スレッドまたは作業項目より、プログラムによる制御を詳細に行うことができる。More programmatic control than is possible with a thread or work item.

    タスクおよびタスクを中心に構築されたフレームワークでは、待機、キャンセル、継続、信頼性の高い例外処理、詳細なステータス、カスタムのスケジュール設定などをサポートする豊富な API が用意されています。Tasks and the framework built around them provide a rich set of APIs that support waiting, cancellation, continuations, robust exception handling, detailed status, custom scheduling, and more.

この 2 つの理由により、.NET Framework では、マルチスレッド、非同期および並列コードを記述するために、TPL で API を使用することをお勧めしています。For both of these reasons, in the .NET Framework, TPL is the preferred API for writing multi-threaded, asynchronous, and parallel code.

暗黙的なタスクの作成と実行Creating and running tasks implicitly

Parallel.Invoke メソッドには、任意の数のステートメントを同時に実行する便利な方法が用意されています。The Parallel.Invoke method provides a convenient way to run any number of arbitrary statements concurrently. 作業項目ごとに Action デリゲートに渡すだけです。Just pass in an Action delegate for each item of work. これらのデリゲートを最も簡単に作成するには、ラムダ式を使用します。The easiest way to create these delegates is to use lambda expressions. ラムダ式では、名前付きメソッドを呼び出したり、コード インラインを指定したりできます。The lambda expression can either call a named method or provide the code inline. 次の例では、2 つのタスクを同時に作成および開始する基本の Invoke 呼び出しを示しています。The following example shows a basic Invoke call that creates and starts two tasks that run concurrently. 最初のタスクは DoSomeWork という名のメソッドを呼び出すラムダ式によって表され、2 番目のタスクは DoSomeOtherWork という名のメソッドを呼び出すラムダ式によって表されます。The first task is represented by a lambda expression that calls a method named DoSomeWork, and the second task is represented by a lambda expression that calls a method named DoSomeOtherWork.

注意

ここでは、ラムダ式を使用して TPL でデリゲートを定義します。This documentation uses lambda expressions to define delegates in TPL. C# または Visual Basic のラムダ式についての情報が必要な場合は、「Lambda Expressions in PLINQ and TPL (PLINQ および TPL のラムダ式)」を参照してください。If you are not familiar with lambda expressions in C# or Visual Basic, see Lambda Expressions in PLINQ and TPL.

Parallel.Invoke(() => DoSomeWork(), () => DoSomeOtherWork());
Parallel.Invoke(Sub() DoSomeWork(), Sub() DoSomeOtherWork())

注意

Task によって背後で作成される Invoke インスタンスの数は、指定するデリゲートの数と等しくなくてもかまいません。The number of Task instances that are created behind the scenes by Invoke is not necessarily equal to the number of delegates that are provided. TPL では、特に多数のデリゲートによるさまざまな最適化方法を採用しています。The TPL may employ various optimizations, especially with large numbers of delegates.

詳細については、「方法 :Parallel.Invoke を使用して並列操作を実行する」を参照してください。For more information, see How to: Use Parallel.Invoke to Execute Parallel Operations.

タスクの実行をさらに制御する場合、またはタスクから値を返す場合、Task オブジェクトをより明示的に操作する必要があります。For greater control over task execution or to return a value from the task, you have to work with Task objects more explicitly.

明示的なタスクの作成と実行Creating and running tasks explicitly

値を返さないタスクは、System.Threading.Tasks.Task クラスによって表されます。A task that does not return a value is represented by the System.Threading.Tasks.Task class. 値を返すタスクは、System.Threading.Tasks.Task<TResult> から継承された Task クラスで表されます。A task that returns a value is represented by the System.Threading.Tasks.Task<TResult> class, which inherits from Task. タスク オブジェクトはインフラストラクチャの詳細を処理し、タスクの有効期間内に呼び出し元のスレッドからアクセスできるメソッドとプロパティを提供します。The task object handles the infrastructure details and provides methods and properties that are accessible from the calling thread throughout the lifetime of the task. たとえば、タスクの Status プロパティに任意のタイミングでアクセスして、タスクが開始されたか、完了まで実行されたか、取り消されたか、または例外がスローされたかどうかを確認できます。For example, you can access the Status property of a task at any time to determine whether it has started running, ran to completion, was canceled, or has thrown an exception. 状態は、TaskStatus 列挙型によって表されます。The status is represented by a TaskStatus enumeration.

タスクを作成するときは、タスクが実行するコードをカプセル化するユーザー デリゲートを指定します。When you create a task, you give it a user delegate that encapsulates the code that the task will execute. このデリゲートは名前付きデリゲート、匿名メソッド、またはラムダ式として表すことができます。The delegate can be expressed as a named delegate, an anonymous method, or a lambda expression. ラムダ式には、次の例で示すような名前付きメソッドへの呼び出しを含めることができます。Lambda expressions can contain a call to a named method, as shown in the following example. この例は Task.Wait メソッドの呼び出しを含み、コンソール モードのアプリケーションが終了する前にタスクの実行が完了するようにしていることに注意してください。Note that the example includes a call to the Task.Wait method to ensure that the task completes execution before the console mode application ends.

using System;
using System.Threading;
using System.Threading.Tasks;

public class Example
{
   public static void Main()
   {
      Thread.CurrentThread.Name = "Main";

      // Create a task and supply a user delegate by using a lambda expression. 
      Task taskA = new Task( () => Console.WriteLine("Hello from taskA."));
      // Start the task.
      taskA.Start();

      // Output a message from the calling thread.
      Console.WriteLine("Hello from thread '{0}'.", 
                        Thread.CurrentThread.Name);
      taskA.Wait();
   }
}
// The example displays output like the following:
//       Hello from thread 'Main'.
//       Hello from taskA.
Imports System.Threading
Imports System.Threading.Tasks

Module Example
   Public Sub Main()
        Thread.CurrentThread.Name = "Main"
        
        ' Create a task and supply a user delegate by using a lambda expression. 
        Dim taskA = New Task(Sub() Console.WriteLine("Hello from taskA."))
        ' Start the task.
        taskA.Start()

        ' Output a message from the calling thread.
        Console.WriteLine("Hello from thread '{0}'.", 
                          Thread.CurrentThread.Name)
        taskA.Wait()
   End Sub
End Module
' The example displays output like the following:
'    Hello from thread 'Main'.
'    Hello from taskA.

Task.Run メソッドを使用して、一度の操作でタスクを作成および開始することもできます。You can also use the Task.Run methods to create and start a task in one operation. タスクを管理するため、Run メソッドは、現在のスレッドに関連付けられたタスク スケジューラにかかわらず、既定のタスク スケジューラを使用します。To manage the task, the Run methods use the default task scheduler, regardless of which task scheduler is associated with the current thread. Run メソッドは、タスクの作成とスケジュールの詳細な制御が必要ない場合に、タスクを作成および開始するために適しています。The Run methods are the preferred way to create and start tasks when more control over the creation and scheduling of the task is not needed.

using System;
using System.Threading;
using System.Threading.Tasks;

public class Example
{
   public static void Main()
   {
      Thread.CurrentThread.Name = "Main";

      // Define and run the task.
      Task taskA = Task.Run( () => Console.WriteLine("Hello from taskA."));

      // Output a message from the calling thread.
      Console.WriteLine("Hello from thread '{0}'.", 
                          Thread.CurrentThread.Name);
      taskA.Wait();
   }
}
// The example displays output like the following:
//       Hello from thread 'Main'.
//       Hello from taskA.
Imports System.Threading
Imports System.Threading.Tasks

Module Example
   Public Sub Main()
        Thread.CurrentThread.Name = "Main"
        
        Dim taskA As Task = Task.Run(Sub() Console.WriteLine("Hello from taskA."))

        ' Output a message from the calling thread.
        Console.WriteLine("Hello from thread '{0}'.", 
                          Thread.CurrentThread.Name)
        taskA.Wait()
   End Sub
End Module
' The example displays output like the following:
'    Hello from thread 'Main'.
'    Hello from taskA.

TaskFactory.StartNew メソッドを使用して、一度の操作でタスクを作成および開始することもできます。You can also use the TaskFactory.StartNew method to create and start a task in one operation. 次の例に示すように、作成とスケジュール設定を分ける必要がない場合、追加のタスク作成オプションまたは特定のスケジューラを使う必要がある場合、または Task.AsyncState プロパティを使用して取得できるタスクに追加の状態を渡す必要がある場合は、このメソッドを使用します。Use this method when creation and scheduling do not have to be separated and you require additional task creation options or the use of a specific scheduler, or when you need to pass additional state into the task that you can retrieve through its Task.AsyncState property, as shown in the following example.

using System;
using System.Threading;
using System.Threading.Tasks;

class CustomData
{
   public long CreationTime;
   public int Name; 
   public int ThreadNum;
}

public class Example
{
   public static void Main()
   {
      Task[] taskArray = new Task[10];
      for (int i = 0; i < taskArray.Length; i++) {
         taskArray[i] = Task.Factory.StartNew( (Object obj ) => {
                                                  CustomData data = obj as CustomData;
                                                  if (data == null) 
                                                     return;
                                     
                                                  data.ThreadNum = Thread.CurrentThread.ManagedThreadId;
                                               },
                                               new CustomData() {Name = i, CreationTime = DateTime.Now.Ticks} );
      }
      Task.WaitAll(taskArray);     
      foreach (var task in taskArray) {
         var data = task.AsyncState as CustomData;
         if (data != null)
            Console.WriteLine("Task #{0} created at {1}, ran on thread #{2}.",
                              data.Name, data.CreationTime, data.ThreadNum);
      }                     
   }
}
// The example displays output like the following:
//       Task #0 created at 635116412924597583 on thread #3.
//       Task #1 created at 635116412924607584 on thread #4.
//       Task #3 created at 635116412924607584 on thread #4.
//       Task #4 created at 635116412924607584 on thread #4.
//       Task #2 created at 635116412924607584 on thread #3.
//       Task #6 created at 635116412924607584 on thread #3.
//       Task #5 created at 635116412924607584 on thread #4.
//       Task #8 created at 635116412924607584 on thread #4.
//       Task #7 created at 635116412924607584 on thread #3.
//       Task #9 created at 635116412924607584 on thread #4.
Imports System.Threading
Imports System.Threading.Tasks

Class CustomData
   Public CreationTime As Long
   Public Name As Integer
   Public ThreadNum As Integer
End Class

Module Example
   Public Sub Main()
      Dim taskArray(9) As Task
      For i As Integer = 0 To taskArray.Length - 1
         taskArray(i) = Task.Factory.StartNew(Sub(obj As Object)
                                                 Dim data As CustomData = TryCast(obj, CustomData)
                                                 If data Is Nothing Then Return
                                     
                                                 data.ThreadNum = Thread.CurrentThread.ManagedThreadId
                                              End Sub,
                                              New CustomData With {.Name = i, .CreationTime = DateTime.Now.Ticks} )
      Next
      Task.WaitAll(taskArray)     

      For Each task In taskArray
         Dim data = TryCast(task.AsyncState, CustomData)
         If data IsNot Nothing Then
            Console.WriteLine("Task #{0} created at {1}, ran on thread #{2}.",
                              data.Name, data.CreationTime, data.ThreadNum)
         End If
      Next
   End Sub
End Module
' The example displays output like the following:
'    Task #0 created at 635116451245250515, ran on thread #3, RanToCompletion
'    Task #1 created at 635116451245270515, ran on thread #4, RanToCompletion
'    Task #2 created at 635116451245270515, ran on thread #3, RanToCompletion
'    Task #3 created at 635116451245270515, ran on thread #3, RanToCompletion
'    Task #4 created at 635116451245270515, ran on thread #3, RanToCompletion
'    Task #5 created at 635116451245270515, ran on thread #3, RanToCompletion
'    Task #6 created at 635116451245270515, ran on thread #3, RanToCompletion
'    Task #7 created at 635116451245270515, ran on thread #3, RanToCompletion
'    Task #8 created at 635116451245270515, ran on thread #3, RanToCompletion
'    Task #9 created at 635116451245270515, ran on thread #3, RanToCompletion

Task および Task<TResult> はそれぞれ、Factory の既定のインスタンスを返す、静的な TaskFactory プロパティを公開するので、メソッドを Task.Factory.StartNew() として呼び出すことができます。Task and Task<TResult> each expose a static Factory property that returns a default instance of TaskFactory, so that you can call the method as Task.Factory.StartNew(). また、次の例のタスクは System.Threading.Tasks.Task<TResult> 型であるため、それぞれのタスクは計算の結果を格納するパブリックな Task<TResult>.Result プロパティを持ちます。Also, in the following example, because the tasks are of type System.Threading.Tasks.Task<TResult>, they each have a public Task<TResult>.Result property that contains the result of the computation. タスクは非同期に実行され、任意の順序で完了されることがあります。The tasks run asynchronously and may complete in any order. 計算が終了する前に Result プロパティにアクセスした場合、このプロパティは値が使用可能な状態になるまで呼び出しスレッドをブロックします。If the Result property is accessed before the computation finishes, the property blocks the calling thread until the value is available.

using System;
using System.Threading.Tasks;

public class Example
{
   public static void Main()
   {
        Task<Double>[] taskArray = { Task<Double>.Factory.StartNew(() => DoComputation(1.0)),
                                     Task<Double>.Factory.StartNew(() => DoComputation(100.0)), 
                                     Task<Double>.Factory.StartNew(() => DoComputation(1000.0)) };

        var results = new Double[taskArray.Length];
        Double sum = 0;
        
        for (int i = 0; i < taskArray.Length; i++) {
            results[i] = taskArray[i].Result;
            Console.Write("{0:N1} {1}", results[i], 
                              i == taskArray.Length - 1 ? "= " : "+ ");
            sum += results[i];
        }
        Console.WriteLine("{0:N1}", sum);
   }

   private static Double DoComputation(Double start)
   {
      Double sum = 0;
      for (var value = start; value <= start + 10; value += .1)
         sum += value;

      return sum; 
   }
}
// The example displays the following output:
//        606.0 + 10,605.0 + 100,495.0 = 111,706.0
Imports System.Threading.Tasks

Module Example
   Public Sub Main()
        Dim taskArray() = { Task(Of Double).Factory.StartNew(Function() DoComputation(1.0)),
                            Task(Of Double).Factory.StartNew(Function() DoComputation(100.0)), 
                            Task(Of Double).Factory.StartNew(Function() DoComputation(1000.0)) }

        Dim results(taskArray.Length - 1) As Double
        Dim sum As Double
        
        For i As Integer = 0 To taskArray.Length - 1
            results(i) = taskArray(i).Result
            Console.Write("{0:N1} {1}", results(i), 
                              If(i = taskArray.Length - 1, "= ", "+ "))
            sum += results(i)
        Next
        Console.WriteLine("{0:N1}", sum)
   End Sub
   
   Private Function DoComputation(start As Double) As Double
      Dim sum As Double
      For value As Double = start To start + 10 Step .1
         sum += value
      Next
      Return sum 
   End Function
End Module
' The example displays the following output:
'       606.0 + 10,605.0 + 100,495.0 = 111,706.0

詳細については、「方法 :タスクから値を返す」を参照してください。For more information, see How to: Return a Value from a Task.

ラムダ式を使用してデリゲートを作成すると、ソース コード内の該当ポイントで参照できるすべての変数にアクセスできます。When you use a lambda expression to create a delegate, you have access to all the variables that are visible at that point in your source code. ただし、特にループ内では、ラムダによって変数が予想どおりにキャプチャされない場合があります。However, in some cases, most notably within loops, a lambda doesn't capture the variable as expected. ラムダでは、反復処理が実行されるたびに変更された値をキャプチャするのではなく、最終値だけがキャプチャされます。It only captures the final value, not the value as it mutates after each iteration. この問題を説明する例を次に示します。The following example illustrates the problem. これは CustomData オブジェクトをインスタンス化するラムダ式にループ カウンターを渡し、オブジェクトの識別子としてループ カウンターを使用します。It passes a loop counter to a lambda expression that instantiates a CustomData object and uses the loop counter as the object's identifier. この例の出力結果が示すように、CustomData の各オブジェクトは同じ識別子を持ちます。As the output from the example shows, each CustomData object has an identical identifier.

using System;
using System.Threading;
using System.Threading.Tasks;

class CustomData
{
   public long CreationTime;
   public int Name; 
   public int ThreadNum;
}

public class Example
{
   public static void Main()
   {
      // Create the task object by using an Action(Of Object) to pass in the loop
      // counter. This produces an unexpected result.
      Task[] taskArray = new Task[10];
      for (int i = 0; i < taskArray.Length; i++) {
         taskArray[i] = Task.Factory.StartNew( (Object obj) => {
                                                 var data = new CustomData() {Name = i, CreationTime = DateTime.Now.Ticks}; 
                                                 data.ThreadNum = Thread.CurrentThread.ManagedThreadId;
                                                 Console.WriteLine("Task #{0} created at {1} on thread #{2}.",
                                                                   data.Name, data.CreationTime, data.ThreadNum);
                                               },
                                              i );
      }
      Task.WaitAll(taskArray);     
   }
}
// The example displays output like the following:
//       Task #10 created at 635116418427727841 on thread #4.
//       Task #10 created at 635116418427737842 on thread #4.
//       Task #10 created at 635116418427737842 on thread #4.
//       Task #10 created at 635116418427737842 on thread #4.
//       Task #10 created at 635116418427737842 on thread #4.
//       Task #10 created at 635116418427737842 on thread #4.
//       Task #10 created at 635116418427727841 on thread #3.
//       Task #10 created at 635116418427747843 on thread #3.
//       Task #10 created at 635116418427747843 on thread #3.
//       Task #10 created at 635116418427737842 on thread #4.
Imports System.Threading
Imports System.Threading.Tasks

Class CustomData
   Public CreationTime As Long
   Public Name As Integer
   Public ThreadNum As Integer
End Class

Module Example
   Public Sub Main()
      ' Create the task object by using an Action(Of Object) to pass in the loop
      ' counter. This produces an unexpected result.
      Dim taskArray(9) As Task
      For i As Integer = 0 To taskArray.Length - 1
         taskArray(i) = Task.Factory.StartNew(Sub(obj As Object)
                                                 Dim data As New CustomData With {.Name = i, .CreationTime = DateTime.Now.Ticks} 
                                                 data.ThreadNum = Thread.CurrentThread.ManagedThreadId
                                                 Console.WriteLine("Task #{0} created at {1} on thread #{2}.",
                                                                   data.Name, data.CreationTime, data.ThreadNum)
                                              End Sub,
                                              i )
      Next
      Task.WaitAll(taskArray)     
   End Sub
End Module
' The example displays output like the following:
'       Task #10 created at 635116418427727841 on thread #4.
'       Task #10 created at 635116418427737842 on thread #4.
'       Task #10 created at 635116418427737842 on thread #4.
'       Task #10 created at 635116418427737842 on thread #4.
'       Task #10 created at 635116418427737842 on thread #4.
'       Task #10 created at 635116418427737842 on thread #4.
'       Task #10 created at 635116418427727841 on thread #3.
'       Task #10 created at 635116418427747843 on thread #3.
'       Task #10 created at 635116418427747843 on thread #3.
'       Task #10 created at 635116418427737842 on thread #4.

反復処理が実行されるたびに値にアクセスできるようにするには、コンストラクターによって状態オブジェクトをタスクに提供します。You can access the value on each iteration by providing a state object to a task through its constructor. 次の例では、ラムダ式に渡される CustomData オブジェクトを作成するときに、ループ カウンターを使用して前の例を変更しています。The following example modifies the previous example by using the loop counter when creating the CustomData object, which, in turn, is passed to the lambda expression. この例の出力結果が示すように、CustomData の各オブジェクトは、オブジェクトがインスタンス化されたときのループ カウンターの値に基づいて、一意の識別子を持ちます。As the output from the example shows, each CustomData object now has a unique identifier based on the value of the loop counter at the time the object was instantiated.

using System;
using System.Threading;
using System.Threading.Tasks;

class CustomData
{
   public long CreationTime;
   public int Name; 
   public int ThreadNum;
}

public class Example
{
   public static void Main()
   {
      // Create the task object by using an Action(Of Object) to pass in custom data
      // to the Task constructor. This is useful when you need to capture outer variables
      // from within a loop. 
      Task[] taskArray = new Task[10];
      for (int i = 0; i < taskArray.Length; i++) {
         taskArray[i] = Task.Factory.StartNew( (Object obj ) => {
                                                  CustomData data = obj as CustomData;
                                                  if (data == null) 
                                                     return;
                                     
                                                  data.ThreadNum = Thread.CurrentThread.ManagedThreadId;
                                                  Console.WriteLine("Task #{0} created at {1} on thread #{2}.",
                                                                   data.Name, data.CreationTime, data.ThreadNum);
                                               },
                                               new CustomData() {Name = i, CreationTime = DateTime.Now.Ticks} );
      }
      Task.WaitAll(taskArray);     
   }
}
// The example displays output like the following:
//       Task #0 created at 635116412924597583 on thread #3.
//       Task #1 created at 635116412924607584 on thread #4.
//       Task #3 created at 635116412924607584 on thread #4.
//       Task #4 created at 635116412924607584 on thread #4.
//       Task #2 created at 635116412924607584 on thread #3.
//       Task #6 created at 635116412924607584 on thread #3.
//       Task #5 created at 635116412924607584 on thread #4.
//       Task #8 created at 635116412924607584 on thread #4.
//       Task #7 created at 635116412924607584 on thread #3.
//       Task #9 created at 635116412924607584 on thread #4.
Imports System.Threading
Imports System.Threading.Tasks

Class CustomData
   Public CreationTime As Long
   Public Name As Integer
   Public ThreadNum As Integer
End Class

Module Example
   Public Sub Main()
      ' Create the task object by using an Action(Of Object) to pass in custom data
      ' to the Task constructor. This is useful when you need to capture outer variables
      ' from within a loop. 
      Dim taskArray(9) As Task
      For i As Integer = 0 To taskArray.Length - 1
         taskArray(i) = Task.Factory.StartNew(Sub(obj As Object)
                                                 Dim data As CustomData = TryCast(obj, CustomData)
                                                 If data Is Nothing Then Return
                                     
                                                 data.ThreadNum = Thread.CurrentThread.ManagedThreadId
                                                 Console.WriteLine("Task #{0} created at {1} on thread #{2}.",
                                                                   data.Name, data.CreationTime, data.ThreadNum)
                                              End Sub,
                                              New CustomData With {.Name = i, .CreationTime = DateTime.Now.Ticks} )
      Next
      Task.WaitAll(taskArray)     
   End Sub
End Module
' The example displays output like the following:
'       Task #0 created at 635116412924597583 on thread #3.
'       Task #1 created at 635116412924607584 on thread #4.
'       Task #3 created at 635116412924607584 on thread #4.
'       Task #4 created at 635116412924607584 on thread #4.
'       Task #2 created at 635116412924607584 on thread #3.
'       Task #6 created at 635116412924607584 on thread #3.
'       Task #5 created at 635116412924607584 on thread #4.
'       Task #8 created at 635116412924607584 on thread #4.
'       Task #7 created at 635116412924607584 on thread #3.
'       Task #9 created at 635116412924607584 on thread #4.

この状態は、タスク デリゲートに引数として渡されます。Task.AsyncState プロパティを使用することで、タスク オブジェクトから状態にアクセスできます。This state is passed as an argument to the task delegate, and it can be accessed from the task object by using the Task.AsyncState property. 次の例は、前の例を変更したものです。The following example is a variation on the previous example. AsyncState プロパティを使用して、ラムダ式に渡される CustomData オブジェクトに関する情報を表示します。It uses the AsyncState property to display information about the CustomData objects passed to the lambda expression.

using System;
using System.Threading;
using System.Threading.Tasks;

class CustomData
{
   public long CreationTime;
   public int Name; 
   public int ThreadNum;
}

public class Example
{
   public static void Main()
   {
      Task[] taskArray = new Task[10];
      for (int i = 0; i < taskArray.Length; i++) {
         taskArray[i] = Task.Factory.StartNew( (Object obj ) => {
                                                  CustomData data = obj as CustomData;
                                                  if (data == null) 
                                                     return;
                                     
                                                  data.ThreadNum = Thread.CurrentThread.ManagedThreadId;
                                               },
                                               new CustomData() {Name = i, CreationTime = DateTime.Now.Ticks} );
      }
      Task.WaitAll(taskArray);     
      foreach (var task in taskArray) {
         var data = task.AsyncState as CustomData;
         if (data != null)
            Console.WriteLine("Task #{0} created at {1}, ran on thread #{2}.",
                              data.Name, data.CreationTime, data.ThreadNum);
      }                     
   }
}
// The example displays output like the following:
//       Task #0 created at 635116412924597583 on thread #3.
//       Task #1 created at 635116412924607584 on thread #4.
//       Task #3 created at 635116412924607584 on thread #4.
//       Task #4 created at 635116412924607584 on thread #4.
//       Task #2 created at 635116412924607584 on thread #3.
//       Task #6 created at 635116412924607584 on thread #3.
//       Task #5 created at 635116412924607584 on thread #4.
//       Task #8 created at 635116412924607584 on thread #4.
//       Task #7 created at 635116412924607584 on thread #3.
//       Task #9 created at 635116412924607584 on thread #4.
Imports System.Threading
Imports System.Threading.Tasks

Class CustomData
   Public CreationTime As Long
   Public Name As Integer
   Public ThreadNum As Integer
End Class

Module Example
   Public Sub Main()
      Dim taskArray(9) As Task
      For i As Integer = 0 To taskArray.Length - 1
         taskArray(i) = Task.Factory.StartNew(Sub(obj As Object)
                                                 Dim data As CustomData = TryCast(obj, CustomData)
                                                 If data Is Nothing Then Return
                                     
                                                 data.ThreadNum = Thread.CurrentThread.ManagedThreadId
                                              End Sub,
                                              New CustomData With {.Name = i, .CreationTime = DateTime.Now.Ticks} )
      Next
      Task.WaitAll(taskArray)     

      For Each task In taskArray
         Dim data = TryCast(task.AsyncState, CustomData)
         If data IsNot Nothing Then
            Console.WriteLine("Task #{0} created at {1}, ran on thread #{2}.",
                              data.Name, data.CreationTime, data.ThreadNum)
         End If
      Next
   End Sub
End Module
' The example displays output like the following:
'    Task #0 created at 635116451245250515, ran on thread #3, RanToCompletion
'    Task #1 created at 635116451245270515, ran on thread #4, RanToCompletion
'    Task #2 created at 635116451245270515, ran on thread #3, RanToCompletion
'    Task #3 created at 635116451245270515, ran on thread #3, RanToCompletion
'    Task #4 created at 635116451245270515, ran on thread #3, RanToCompletion
'    Task #5 created at 635116451245270515, ran on thread #3, RanToCompletion
'    Task #6 created at 635116451245270515, ran on thread #3, RanToCompletion
'    Task #7 created at 635116451245270515, ran on thread #3, RanToCompletion
'    Task #8 created at 635116451245270515, ran on thread #3, RanToCompletion
'    Task #9 created at 635116451245270515, ran on thread #3, RanToCompletion

タスク IDTask ID

各タスクは、アプリケーション ドメイン内で一意に識別され、Task.Id プロパティを使用してアクセスできる整数の ID を受け取ります。Every task receives an integer ID that uniquely identifies it in an application domain and can be accessed by using the Task.Id property. この ID は、Visual Studio デバッガーの [並列スタック] ウィンドウおよび [タスク] ウィンドウでタスク情報を確認する場合に役立ちます。The ID is useful for viewing task information in the Visual Studio debugger Parallel Stacks and Tasks windows. この ID は ID が要求されるまでは作成されません。したがって、タスクの ID はプログラムが実行されるたびに異なる場合があります。The ID is lazily created, which means that it isn't created until it is requested; therefore, a task may have a different ID every time the program is run. デバッガーでタスク ID を表示する方法の詳細については、「[タスク] ウィンドウの使用」と「[並列スタック] ウィンドウの使用」を参照してください。For more information about how to view task IDs in the debugger, see Using the Tasks Window and Using the Parallel Stacks Window.

タスクの作成オプションTask creation options

タスクを作成するほとんどの API には、TaskCreationOptions パラメーターを受け入れるオーバーロードが用意されています。Most APIs that create tasks provide overloads that accept a TaskCreationOptions parameter. これらのオプションのいずれかを指定することで、タスク スケジューラにスレッド プール上のタスクをスケジュールする方法を指示できます。By specifying one of these options, you tell the task scheduler how to schedule the task on the thread pool. タスクの作成オプションの一覧を次に示します。The following table lists the various task creation options.

TaskCreationOptions パラメーター値TaskCreationOptions parameter value 説明Description
None オプションを指定しなかった場合の既定値です。The default when no option is specified. スケジューラは既定のヒューリスティックを使用してタスクをスケジュールします。The scheduler uses its default heuristics to schedule the task.
PreferFairness 先に作成されたタスクが先に実行され、後から作成されたタスクは後から実行されるように、タスクのスケジュールを指定します。Specifies that the task should be scheduled so that tasks created sooner will be more likely to be executed sooner, and tasks created later will be more likely to execute later.
LongRunning 実行に時間のかかる操作を表すタスクであることを示します。Specifies that the task represents a long-running operation.
AttachedToParent 子が存在する場合、現在のタスクにアタッチされた子としてタスクを作成するように指定します。Specifies that a task should be created as an attached child of the current task, if one exists. 詳細については、「アタッチされた子タスクとデタッチされた子タスク」を参照してください。For more information, see Attached and Detached Child Tasks.
DenyChildAttach 内側のタスクが AttachedToParent オプションを指定すると、そのタスクはアタッチされた子タスクにならないことを指定します。Specifies that if an inner task specifies the AttachedToParent option, that task will not become an attached child task.
HideScheduler TaskFactory.StartNew または Task<TResult>.ContinueWith などのメソッドを特定のタスクから呼び出して作成されたタスクのタスク スケジューラは、このタスクが実行されているスケジューラではなく、既定のスケジューラであることを指定します。Specifies that the task scheduler for tasks created by calling methods like TaskFactory.StartNew or Task<TResult>.ContinueWith from within a particular task is the default scheduler instead of the scheduler on which this task is running.

このオプションは、ビットごとの OR 演算を使用して組み合わせることができます。The options may be combined by using a bitwise OR operation. 次の例は、LongRunning オプションと PreferFairness オプションが指定されたタスクを示しています。The following example shows a task that has the LongRunning and PreferFairness option.

var task3 = new Task(() => MyLongRunningMethod(),
                    TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness);
task3.Start();

Dim task3 = New Task(Sub() MyLongRunningMethod(),
                        TaskCreationOptions.LongRunning Or TaskCreationOptions.PreferFairness)
task3.Start()

タスク、スレッド、およびカルチャTasks, threads, and culture

各スレッドにはカルチャと UI カルチャが関連付けられています。それぞれのカルチャは Thread.CurrentCultureThread.CurrentUICulture プロパティにより定義されています。Each thread has an associated culture and UI culture, which is defined by the Thread.CurrentCulture and Thread.CurrentUICulture properties, respectively. スレッドのカルチャは、書式設定、解析、並べ替え、文字列比較などの操作で使用されます。A thread's culture is used in such operations as formatting, parsing, sorting, and string comparison. スレッドの UI カルチャはリソースの検索で使用されます。A thread's UI culture is used in resource lookup. 通常、CultureInfo.DefaultThreadCurrentCulture プロパティと CultureInfo.DefaultThreadCurrentUICulture プロパティを使用してアプリケーション ドメイン内のすべてのスレッドの既定のカルチャを指定していない限り、スレッドの既定のカルチャと既定の UI カルチャはシステム カルチャによって定義されます。Ordinarily, unless you specify a default culture for all the threads in an application domain by using the CultureInfo.DefaultThreadCurrentCulture and CultureInfo.DefaultThreadCurrentUICulture properties, the default culture and UI culture of a thread is defined by the system culture. スレッドのカルチャを明示的に設定して新しいスレッドを開始すると、新しいスレッドは呼び出し元スレッドのカルチャを継承せず、既定のシステム カルチャがそのカルチャとして使用されます。If you explicitly set a thread's culture and launch a new thread, the new thread does not inherit the culture of the calling thread; instead, its culture is the default system culture. .NET Framework 4.6 より前のバージョンの .NET Framework を対象とするアプリのタスク ベース プログラミング モデルは、この方針に準拠します。The task-based programming model for apps that target versions of the .NET Framework prior to .NET Framework 4.6 adhere to this practice.

重要

呼び出し元スレッドのカルチャは、タスクのコンテキストの一部として、.NET Framework 4.6 で実行されるアプリではなく、.NET Framework 4.6 を対象としたアプリに適用されます。Note that the calling thread's culture as part of a task's context applies to apps that target the .NET Framework 4.6, not apps that run under the .NET Framework 4.6. Visual Studio 内部でプロジェクトを作成する場合、 [新しいプロジェクト] ダイアログ ボックスの上部にあるドロップダウン リストから特定バージョンの .NET Framework を選択すると、そのバージョンを対象にできます。また、Visual Studio 外部では TargetFrameworkAttribute 属性を使用できます。You can target a particular version of the .NET Framework when you create your project in Visual Studio by selecting that version from the dropdown list at the top of the New Project dialog box, or outside of Visual Studio you can use the TargetFrameworkAttribute attribute. .NET Framework 4.6 より前のバージョンの .NET Framework を対象とするアプリ、または特定のバージョンの .NET Framework を対象としないアプリでは、タスクのカルチャは継続的に、それが実行されているスレッドのカルチャによって決まります。For apps that target versions of the .NET Framework prior to the .NET Framework 4.6, or that do not target a specific version of the .NET Framework, a task's culture continues to be determined by the culture of the thread on which it runs.

.NET Framework 4.6 以降を対象とするアプリでは、タスクがスレッド プールのスレッドで非同期に実行されている場合でも、呼び出し元スレッドのカルチャが各タスクに継承されます。Starting with apps that target the .NET Framework 4.6, the calling thread's culture is inherited by each task, even if the task runs asynchronously on a thread pool thread.

簡単な例を次に示します。The following example provides a simple illustration. TargetFrameworkAttribute 属性を使用して .NET Framework 4.6 を対象とし、アプリの現在のカルチャをフランス語 (フランス)、またはフランス語 (フランス) が現在のカルチャである場合は英語 (米国) に変更します。It uses the TargetFrameworkAttribute attribute to target the .NET Framework 4.6 and changes the app's current culture to either French (France) or, if French (France) is already the current culture, English (United States). 次に、変更後のカルチャの通貨値として書式設定された数値を返す formatDelegate という名前のデリゲートを呼び出します。It then invokes a delegate named formatDelegate that returns some numbers formatted as currency values in the new culture. デリゲートは、同期タスクまたは非同期タスクのいずれの場合でも、予期される結果を返すことに注意してください。これは、非同期タスクは呼び出し元スレッドのカルチャを継承するためです。Note that whether the delegate as a task either synchronously or asynchronously, it returns the expected result because the culture of the calling thread is inherited by the asynchronous task.

using System;
using System.Globalization;
using System.Runtime.Versioning;
using System.Threading;
using System.Threading.Tasks;

[assembly:TargetFramework(".NETFramework,Version=v4.6")]

public class Example
{
   
   public static void Main()
   {
       decimal[] values = { 163025412.32m, 18905365.59m };
       string formatString = "C2";
       Func<String> formatDelegate = () => { string output = String.Format("Formatting using the {0} culture on thread {1}.\n",
                                                                           CultureInfo.CurrentCulture.Name,
                                                                           Thread.CurrentThread.ManagedThreadId);
                                             foreach (var value in values)
                                                output += String.Format("{0}   ", value.ToString(formatString));
                                                   
                                             output += Environment.NewLine;
                                             return output;
                                           };
       
       Console.WriteLine("The example is running on thread {0}", 
                         Thread.CurrentThread.ManagedThreadId);
       // Make the current culture different from the system culture.
       Console.WriteLine("The current culture is {0}", 
                         CultureInfo.CurrentCulture.Name);
       if (CultureInfo.CurrentCulture.Name == "fr-FR")
          Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
       else
          Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR");

       Console.WriteLine("Changed the current culture to {0}.\n",
                         CultureInfo.CurrentCulture.Name);
       
       // Execute the delegate synchronously.
       Console.WriteLine("Executing the delegate synchronously:");
       Console.WriteLine(formatDelegate());
       
       // Call an async delegate to format the values using one format string.
       Console.WriteLine("Executing a task asynchronously:"); 
       var t1 = Task.Run(formatDelegate);
       Console.WriteLine(t1.Result);
       
       Console.WriteLine("Executing a task synchronously:");
       var t2 = new Task<String>(formatDelegate); 
       t2.RunSynchronously();
       Console.WriteLine(t2.Result);
   }
}
// The example displays the following output:
//         The example is running on thread 1
//         The current culture is en-US
//         Changed the current culture to fr-FR.
//
//         Executing the delegate synchronously:
//         Formatting using the fr-FR culture on thread 1.
//         163 025 412,32 €   18 905 365,59 €
//
//         Executing a task asynchronously:
//         Formatting using the fr-FR culture on thread 3.
//         163 025 412,32 €   18 905 365,59 €
//
//         Executing a task synchronously:
//         Formatting using the fr-FR culture on thread 1.
//         163 025 412,32 €   18 905 365,59 €
// If the TargetFrameworkAttribute statement is removed, the example
// displays the following output:
//          The example is running on thread 1
//          The current culture is en-US
//          Changed the current culture to fr-FR.
//
//          Executing the delegate synchronously:
//          Formatting using the fr-FR culture on thread 1.
//          163 025 412,32 €   18 905 365,59 €
//
//          Executing a task asynchronously:
//          Formatting using the en-US culture on thread 3.
//          $163,025,412.32   $18,905,365.59
//
//          Executing a task synchronously:
//          Formatting using the fr-FR culture on thread 1.
//          163 025 412,32 €   18 905 365,59 €
Imports System.Globalization
Imports System.Runtime.Versioning
Imports System.Threading
Imports System.Threading.Tasks

<Assembly:TargetFramework(".NETFramework,Version=v4.6")>

Module Example
   Public Sub Main()
       Dim values() As Decimal = { 163025412.32d, 18905365.59d }
       Dim formatString As String = "C2"
       Dim formatDelegate As Func(Of String) = Function()
                                                  Dim output As String = String.Format("Formatting using the {0} culture on thread {1}.",
                                                                                       CultureInfo.CurrentCulture.Name,
                                                                                       Thread.CurrentThread.ManagedThreadId)
                                                  output += Environment.NewLine
                                                  For Each value In values
                                                     output += String.Format("{0}   ", value.ToString(formatString))
                                                  Next 
                                                  output += Environment.NewLine
                                                  Return output
                                               End Function
       
       Console.WriteLine("The example is running on thread {0}", 
                         Thread.CurrentThread.ManagedThreadId)
       ' Make the current culture different from the system culture.
       Console.WriteLine("The current culture is {0}", 
                         CultureInfo.CurrentCulture.Name)
       If CultureInfo.CurrentCulture.Name = "fr-FR" Then
          Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US")
       Else
          Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR")
       End If
       Console.WriteLine("Changed the current culture to {0}.",
                         CultureInfo.CurrentCulture.Name)
       Console.WriteLine()                  
       
       ' Execute the delegate synchronously.
       Console.WriteLine("Executing the delegate synchronously:")
       Console.WriteLine(formatDelegate())
       
       ' Call an async delegate to format the values using one format string.
       Console.WriteLine("Executing a task asynchronously:") 
       Dim t1 = Task.Run(formatDelegate)
       Console.WriteLine(t1.Result)
       
       Console.WriteLine("Executing a task synchronously:")
       Dim t2 = New Task(Of String)(formatDelegate) 
       t2.RunSynchronously()
       Console.WriteLine(t2.Result)
   End Sub
End Module
' The example displays the following output:
'          The example is running on thread 1
'          The current culture is en-US
'          Changed the current culture to fr-FR.
'
'          Executing the delegate synchronously:
'          Formatting Imports the fr-FR culture on thread 1.
'          163 025 412,32 €   18 905 365,59 €
'
'          Executing a task asynchronously:
'          Formatting Imports the fr-FR culture on thread 3.
'          163 025 412,32 €   18 905 365,59 €
'
'          Executing a task synchronously:
'          Formatting Imports the fr-FR culture on thread 1.
'          163 025 412,32 €   18 905 365,59 €
' If the TargetFrameworkAttribute statement is removed, the example
' displays the following output:
'          The example is running on thread 1
'          The current culture is en-US
'          Changed the current culture to fr-FR.
'
'          Executing the delegate synchronously:
'          Formatting using the fr-FR culture on thread 1.
'          163 025 412,32 €   18 905 365,59 €
'
'          Executing a task asynchronously:
'          Formatting using the en-US culture on thread 3.
'          $163,025,412.32   $18,905,365.59
'
'          Executing a task synchronously:
'          Formatting using the fr-FR culture on thread 1.
'          163 025 412,32 €   18 905 365,59 €

Visual Studio を使用している場合、プロジェクトを [新しいプロジェクト] ダイアログで作成する際に、TargetFrameworkAttribute 属性を省略して、代わりに .NET Framework 4.6 を対象として選択できます。If you are using Visual Studio, you can omit the TargetFrameworkAttribute attribute and instead select the .NET Framework 4.6 as the target when you create the project in the New Project dialog.

.NET Framework 4.6 より前のバージョンの .NET Framework を対象とするアプリの動作が出力に反映されるようにするため、ソース コードから TargetFrameworkAttribute 属性を削除します。For output that reflects the behavior of apps the target versions of the .NET Framework prior to .NET Framework 4.6, remove the TargetFrameworkAttribute attribute from the source code. 出力には、呼び出し元スレッドのカルチャではなく、既定のシステム カルチャの書式指定規則が反映されます。The output will reflect the formatting conventions of the default system culture, not the culture of the calling thread.

非同期タスクとカルチャの詳細については、「CultureInfo」トピックの「カルチャおよび非同期タスク ベースの操作」を参照してください。For more information on asynchronous tasks and culture, see the "Culture and asynchronous task-based operations" section in the CultureInfo topic.

タスクの継続の作成Creating task continuations

Task.ContinueWith メソッドおよび Task<TResult>.ContinueWith メソッドで、"継続元タスク" が終了したときに開始されるタスクを指定できます。The Task.ContinueWith and Task<TResult>.ContinueWith methods let you specify a task to start when the antecedent task finishes. 継続タスクのデリゲートは継続元タスクへの参照を渡し、継続元タスクのステータスを調査できるようにし、また Task<TResult>.Result プロパティの値を取得して、継続元の出力を継続への入力として使用できるようにします。The delegate of the continuation task is passed a reference to the antecedent task so that it can examine the antecedent task's status and, by retrieving the value of the Task<TResult>.Result property, can use the output of the antecedent as input for the continuation.

次の例では、getData タスクは TaskFactory.StartNew<TResult>(Func<TResult>) メソッドの呼び出しによって開始されます。In the following example, the getData task is started by a call to the TaskFactory.StartNew<TResult>(Func<TResult>) method. processData タスクは getData が終了したときに自動的に開始され、displayDataprocessData が終了したときに開始されます。The processData task is started automatically when getData finishes, and displayData is started when processData finishes. getData は、processData タスクの getData プロパティを使用して Task<TResult>.Result タスクがアクセス可能な、整数の配列を生成します。getData produces an integer array, which is accessible to the processData task through the getData task's Task<TResult>.Result property. processData タスクはその配列を処理し、Task<TResult>.ContinueWith<TNewResult>(Func<Task<TResult>,TNewResult>) メソッドに渡されるラムダ式の戻り値の型から推論される型を持つ結果を返します。The processData task processes that array and returns a result whose type is inferred from the return type of the lambda expression passed to the Task<TResult>.ContinueWith<TNewResult>(Func<Task<TResult>,TNewResult>) method. displayData タスクは、processData が終了したときに自動的に実行され、Tuple<T1,T2,T3> ラムダ式が返した processData オブジェクトは、displayData タスクの processData プロパティを使用して、Task<TResult>.Result タスクからアクセス可能です。The displayData task executes automatically when processData finishes, and the Tuple<T1,T2,T3> object returned by the processData lambda expression is accessible to the displayData task through the processData task's Task<TResult>.Result property. displayData タスクは processData タスクから結果を受け取り、同様の方法を使用して (プログラムで使用できるようになったと) 推論される型を持つ結果を Result プロパティで生成します。The displayData task takes the result of the processData task and produces a result whose type is inferred in a similar manner and which is made available to the program in the Result property.

using System;
using System.Threading.Tasks;

public class Example
{
   public static void Main()
   {                         
      var getData = Task.Factory.StartNew(() => { 
                                             Random rnd = new Random(); 
                                             int[] values = new int[100];
                                             for (int ctr = 0; ctr <= values.GetUpperBound(0); ctr++)
                                                values[ctr] = rnd.Next();

                                             return values;
                                          } );  
      var processData = getData.ContinueWith((x) => {
                                                int n = x.Result.Length;
                                                long sum = 0;
                                                double mean;
                                  
                                                for (int ctr = 0; ctr <= x.Result.GetUpperBound(0); ctr++)
                                                   sum += x.Result[ctr];

                                                mean = sum / (double) n;
                                                return Tuple.Create(n, sum, mean);
                                             } ); 
      var displayData = processData.ContinueWith((x) => {
                                                    return String.Format("N={0:N0}, Total = {1:N0}, Mean = {2:N2}",
                                                                         x.Result.Item1, x.Result.Item2, 
                                                                         x.Result.Item3);
                                                 } );                         
      Console.WriteLine(displayData.Result);
   }
}
// The example displays output similar to the following:
//    N=100, Total = 110,081,653,682, Mean = 1,100,816,536.82
Imports System.Threading.Tasks

Module Example
   Public Sub Main()
      Dim getData = Task.Factory.StartNew(Function() 
                                             Dim rnd As New Random()
                                             Dim values(99) As Integer
                                             For ctr = 0 To values.GetUpperBound(0)
                                                values(ctr) = rnd.Next()
                                             Next
                                             Return values
                                          End Function)  
      Dim processData = getData.ContinueWith(Function(x)
                                                Dim n As Integer = x.Result.Length
                                                Dim sum As Long
                                                Dim mean As Double
                                  
                                                For ctr = 0 To x.Result.GetUpperBound(0)
                                                   sum += x.Result(ctr)
                                                Next
                                                mean = sum / n
                                                Return Tuple.Create(n, sum, mean)
                                             End Function) 
      Dim displayData = processData.ContinueWith(Function(x)
                                                    Return String.Format("N={0:N0}, Total = {1:N0}, Mean = {2:N2}",
                                                                         x.Result.Item1, x.Result.Item2, 
                                                                         x.Result.Item3)
                                                 End Function)                         
      Console.WriteLine(displayData.Result)
   End Sub                        
End Module
' The example displays output like the following:
'   N=100, Total = 110,081,653,682, Mean = 1,100,816,536.82

Task.ContinueWith がインスタンス メソッドであるため、Task<TResult> のオブジェクトをそれぞれの継続元タスクにインスタンス化する代わりに、メソッド呼び出しを連結することができます。Because Task.ContinueWith is an instance method, you can chain method calls together instead of instantiating a Task<TResult> object for each antecedent task. 次の例は前の例と機能的には同じものですが、呼び出しを Task.ContinueWith メソッドに連結している点が異なります。The following example is functionally identical to the previous example, except that it chains together calls to the Task.ContinueWith method. メソッドの呼び出しチェーンによって返される Task<TResult> オブジェクトが最終的な継続タスクであることに注意してください。Note that the Task<TResult> object returned by the chain of method calls is the final continuation task.

using System;
using System.Threading.Tasks;

public class Example
{
   public static void Main()
   {                         
      var displayData = Task.Factory.StartNew(() => { 
                                                 Random rnd = new Random(); 
                                                 int[] values = new int[100];
                                                 for (int ctr = 0; ctr <= values.GetUpperBound(0); ctr++)
                                                    values[ctr] = rnd.Next();

                                                 return values;
                                              } ).  
                        ContinueWith((x) => {
                                        int n = x.Result.Length;
                                        long sum = 0;
                                        double mean;
                                  
                                        for (int ctr = 0; ctr <= x.Result.GetUpperBound(0); ctr++)
                                           sum += x.Result[ctr];

                                        mean = sum / (double) n;
                                        return Tuple.Create(n, sum, mean);
                                     } ). 
                        ContinueWith((x) => {
                                        return String.Format("N={0:N0}, Total = {1:N0}, Mean = {2:N2}",
                                                             x.Result.Item1, x.Result.Item2, 
                                                             x.Result.Item3);
                                     } );                         
      Console.WriteLine(displayData.Result);
   }
}
// The example displays output similar to the following:
//    N=100, Total = 110,081,653,682, Mean = 1,100,816,536.82
Imports System.Threading.Tasks

Module Example
   Public Sub Main()
      Dim displayData = Task.Factory.StartNew(Function() 
                                                 Dim rnd As New Random()
                                                 Dim values(99) As Integer
                                                 For ctr = 0 To values.GetUpperBound(0)
                                                    values(ctr) = rnd.Next()
                                                 Next
                                                 Return values
                                              End Function). _  
                        ContinueWith(Function(x)
                                        Dim n As Integer = x.Result.Length
                                        Dim sum As Long
                                        Dim mean As Double
                                  
                                        For ctr = 0 To x.Result.GetUpperBound(0)
                                           sum += x.Result(ctr)
                                        Next
                                        mean = sum / n
                                        Return Tuple.Create(n, sum, mean)
                                     End Function). _ 
                        ContinueWith(Function(x)
                                        Return String.Format("N={0:N0}, Total = {1:N0}, Mean = {2:N2}",
                                                             x.Result.Item1, x.Result.Item2,  
                                                             x.Result.Item3)
                                     End Function)                         
      Console.WriteLine(displayData.Result)
   End Sub                        
End Module
' The example displays output like the following:
'   N=100, Total = 110,081,653,682, Mean = 1,100,816,536.82

ContinueWhenAll メソッドおよび ContinueWhenAny メソッドを使用すると、複数のタスクから継続できます。The ContinueWhenAll and ContinueWhenAny methods enable you to continue from multiple tasks.

詳細については、「継続タスクを使用したタスクの連結」を参照してください。For more information, see Chaining Tasks by Using Continuation Tasks.

デタッチされた子タスクの作成Creating detached child tasks

タスクで実行中のユーザー コードで新しいタスクを作成し、AttachedToParent オプションを指定しない場合、新しいタスクはどのような方法でも親タスクとは同期されません。When user code that is running in a task creates a new task and does not specify the AttachedToParent option, the new task is not synchronized with the parent task in any special way. 非同期タスクのこの型は、デタッチされた入れ子のタスク、またはデタッチされた子タスクと呼ばれます。This type of non-synchronized task is called a detached nested task or detached child task. 次の例は、デタッチされた子タスクを 1 つ作成するタスクを示しています。The following example shows a task that creates one detached child task.

var outer = Task.Factory.StartNew(() =>
{
    Console.WriteLine("Outer task beginning.");

    var child = Task.Factory.StartNew(() =>
    {
        Thread.SpinWait(5000000);
        Console.WriteLine("Detached task completed.");
    });

});

outer.Wait();
Console.WriteLine("Outer task completed.");
// The example displays the following output:
//    Outer task beginning.
//    Outer task completed.
//    Detached task completed.
Dim outer = Task.Factory.StartNew(Sub()
                                      Console.WriteLine("Outer task beginning.")
                                      Dim child = Task.Factory.StartNew(Sub()
                                                                            Thread.SpinWait(5000000)
                                                                            Console.WriteLine("Detached task completed.")
                                                                        End Sub)
                                  End Sub)
outer.Wait()
Console.WriteLine("Outer task completed.")
' The example displays the following output:
'     Outer task beginning.
'     Outer task completed.
'    Detached child completed.

親タスクはデタッチされた子タスクの終了を待機しないことに注意してください。Note that the parent task does not wait for the detached child task to finish.

子タスクの作成Creating child tasks

タスクで実行中のユーザー コードで AttachedToParent オプションを使用してタスクを作成すると、新しいタスクは親タスクに "アタッチされた子タスク" になります。When user code that is running in a task creates a task with the AttachedToParent option, the new task is known as a attached child task of the parent task. AttachedToParent オプションを使用すると、構成されたタスクの並列化を表現できます。親タスクは、すべてのアタッチされた子タスクが終了するのを暗黙的に待機するためです。You can use the AttachedToParent option to express structured task parallelism, because the parent task implicitly waits for all attached child tasks to finish. 次の例は、アタッチされた子タスクを 10 個作成する親タスクを示しています。The following example shows a parent task that creates ten attached child tasks. この例は Task.Wait メソッドを呼び出して親タスクの完了を待機しているが、アタッチされた子タスクの完了を明示的には待機する必要がないことに注意してください。Note that although the example calls the Task.Wait method to wait for the parent task to finish, it does not have to explicitly wait for the attached child tasks to complete.

using System;
using System.Threading;
using System.Threading.Tasks;

public class Example
{
   public static void Main()
   {
      var parent = Task.Factory.StartNew(() => {
                      Console.WriteLine("Parent task beginning.");
                      for (int ctr = 0; ctr < 10; ctr++) {
                         int taskNo = ctr;
                         Task.Factory.StartNew((x) => {
                                                  Thread.SpinWait(5000000);
                                                  Console.WriteLine("Attached child #{0} completed.", 
                                                                    x);
                                               },
                                               taskNo, TaskCreationOptions.AttachedToParent);
                      }
                   });

      parent.Wait();
      Console.WriteLine("Parent task completed.");
   }
}
// The example displays output like the following:
//       Parent task beginning.
//       Attached child #9 completed.
//       Attached child #0 completed.
//       Attached child #8 completed.
//       Attached child #1 completed.
//       Attached child #7 completed.
//       Attached child #2 completed.
//       Attached child #6 completed.
//       Attached child #3 completed.
//       Attached child #5 completed.
//       Attached child #4 completed.
//       Parent task completed.
Imports System.Threading
Imports System.Threading.Tasks

Module Example
   Public Sub Main()
      Dim parent = Task.Factory.StartNew(Sub()
                                            Console.WriteLine("Parent task beginning.")
                                            For ctr As Integer = 0 To 9
                                               Dim taskNo As Integer = ctr
                                               Task.Factory.StartNew(Sub(x)
                                                                        Thread.SpinWait(5000000)
                                                                        Console.WriteLine("Attached child #{0} completed.", 
                                                                                          x)
                                                                     End Sub,
                                                                     taskNo, TaskCreationOptions.AttachedToParent)
                                            Next
                                         End Sub)
      parent.Wait()
      Console.WriteLine("Parent task completed.")
   End Sub
End Module   
' The example displays output like the following:
'       Parent task beginning.
'       Attached child #9 completed.
'       Attached child #0 completed.
'       Attached child #8 completed.
'       Attached child #1 completed.
'       Attached child #7 completed.
'       Attached child #2 completed.
'       Attached child #6 completed.
'       Attached child #3 completed.
'       Attached child #5 completed.
'       Attached child #4 completed.
'       Parent task completed.

親タスクは TaskCreationOptions.DenyChildAttach オプションを使用して、他のタスクが親タスクにアタッチすることを防ぐことができます。A parent task can use the TaskCreationOptions.DenyChildAttach option to prevent other tasks from attaching to the parent task. 詳細については、「アタッチされた子タスクとデタッチされた子タスク」を参照してください。For more information, see Attached and Detached Child Tasks.

タスクの完了を待機するWaiting for tasks to finish

System.Threading.Tasks.Task 型と System.Threading.Tasks.Task<TResult> 型には、タスクが終了するまで待機できる Task.Wait メソッドのオーバーロードがいくつか用意されています。The System.Threading.Tasks.Task and System.Threading.Tasks.Task<TResult> types provide several overloads of the Task.Wait methods that enable you to wait for a task to finish. さらに、静的な Task.WaitAll メソッドおよび Task.WaitAny メソッドのオーバーロードにより、一部またはすべてのタスクの配列が終了するまで待機できます。In addition, overloads of the static Task.WaitAll and Task.WaitAny methods let you wait for any or all of an array of tasks to finish.

通常は、タスクを待機するのは次のいずれかの場合です。Typically, you would wait for a task for one of these reasons:

  • メイン スレッドが、タスクで計算される最終的な結果に依存する。The main thread depends on the final result computed by a task.

  • タスクからスローされる可能性のある例外を処理する必要がある。You have to handle exceptions that might be thrown from the task.

  • アプリケーションは、すべてのタスクが実行を完了する前に終了する場合があります。The application may terminate before all tasks have completed execution. たとえば、コンソール アプリケーションは Main (アプリケーションのエントリ ポイント) のすべての同期コードが実行されると、すぐに終了します。For example, console applications will terminate as soon as all synchronous code in Main (the application entry point) has executed.

次の例は、例外処理を含まない基本的なパターンを示しています。The following example shows the basic pattern that does not involve exception handling.

Task[] tasks = new Task[3]
{
    Task.Factory.StartNew(() => MethodA()),
    Task.Factory.StartNew(() => MethodB()),
    Task.Factory.StartNew(() => MethodC())
};

//Block until all tasks complete.
Task.WaitAll(tasks);

// Continue on this thread...
Dim tasks() =
{
    Task.Factory.StartNew(Sub() MethodA()),
    Task.Factory.StartNew(Sub() MethodB()),
    Task.Factory.StartNew(Sub() MethodC())
}

' Block until all tasks complete.
Task.WaitAll(tasks)

' Continue on this thread...

例外処理を示す例については、例外処理に関する記事を参照してください。For an example that shows exception handling, see Exception Handling.

タイムアウトを指定できるオーバーロードおよび別の CancellationToken を入力パラメーターとして受け取るオーバーロードの中には、プログラムによって、またはユーザーの入力に応答して待機自体を取り消すことができるものがあります。Some overloads let you specify a time-out, and others take an additional CancellationToken as an input parameter, so that the wait itself can be canceled either programmatically or in response to user input.

タスクを待機する場合は、TaskCreationOptions.AttachedToParent オプションを使用して作成されたタスクのすべての子タスクを暗黙的に待機します。When you wait for a task, you implicitly wait for all children of that task that were created by using the TaskCreationOptions.AttachedToParent option. タスクが既に完了している場合、直ちに Task.Wait が返されます。Task.Wait returns immediately if the task has already completed. タスクで発生した例外は、Task.Wait メソッドがタスクの完了後に呼び出された場合でも Task.Wait メソッドによってスローされます。Any exceptions raised by a task will be thrown by a Task.Wait method, even if the Task.Wait method was called after the task completed.

タスクを構成するComposing tasks

TaskTask<TResult> クラスは複数のメソッドを提供し、共通のパターンを実装したり、C#、Visual Basic、F# によって提供される非同期言語機能を使うために、複数のタスクを構成したりするのに役立ちます。The Task and Task<TResult> classes provide several methods that can help you compose multiple tasks to implement common patterns and to better use the asynchronous language features that are provided by C#, Visual Basic, and F#. このセクションでは WhenAllWhenAnyDelay および FromResult メソッドについて説明します。This section describes the WhenAll, WhenAny, Delay, and FromResult methods.

Task.WhenAllTask.WhenAll

Task.WhenAll メソッドは、複数の Task または Task<TResult> オブジェクトが終了するのを、非同期的に待機します。The Task.WhenAll method asynchronously waits for multiple Task or Task<TResult> objects to finish. 提供されるオーバーロード バージョンにより、不均一なタスクのセットを待機することができます。It provides overloaded versions that enable you to wait for non-uniform sets of tasks. たとえば、1 回のメソッド呼び出しで完了する、複数の Task および Task<TResult> オブジェクトを待機できます。For example, you can wait for multiple Task and Task<TResult> objects to complete from one method call.

Task.WhenAnyTask.WhenAny

Task.WhenAny メソッドは、複数の Task の 1 つ、または Task<TResult> オブジェクトが終了するのを、非同期的に待機します。The Task.WhenAny method asynchronously waits for one of multiple Task or Task<TResult> objects to finish. Task.WhenAll メソッドと同様に、このメソッドはオーバーロード バージョンを提供し、これによって不均一なタスクのセットを待機することができます。As in the Task.WhenAll method, this method provides overloaded versions that enable you to wait for non-uniform sets of tasks. WhenAny メソッドは、特に次のシナリオに役立ちます。The WhenAny method is especially useful in the following scenarios.

  • 重複した操作。Redundant operations. 多くの方法で実行できるアルゴリズムまたは操作を検討してください。Consider an algorithm or operation that can be performed in many ways. WhenAny メソッドを使用すると、最初の操作を完了して残りの操作を取り消すように、操作を選択できます。You can use the WhenAny method to select the operation that finishes first and then cancel the remaining operations.

  • インタリーブされた操作。Interleaved operations. 複数の操作を開始して、それらの操作のすべてが完了し、各操作が完了したら WhenAny メソッドを使って結果を処理できるようにします。You can start multiple operations that must all finish and use the WhenAny method to process results as each operation finishes. 1 つの操作が完了したら、1 つ以上の追加タスクを開始できます。After one operation finishes, you can start one or more additional tasks.

  • 制限された操作。Throttled operations. WhenAny メソッドを使用して、前のシナリオを拡張し、同時操作の数を制限することができます。You can use the WhenAny method to extend the previous scenario by limiting the number of concurrent operations.

  • 有効期限切れの操作。Expired operations. WhenAny メソッドを使うと、1 つ以上のタスクと特定の時間後に終了する 1 つのタスクから選択できます。たとえば、Delay メソッドが返すタスクなどです。You can use the WhenAny method to select between one or more tasks and a task that finishes after a specific time, such as a task that is returned by the Delay method. Delay メソッドについては、次のセクションで説明します。The Delay method is described in the following section.

Task.DelayTask.Delay

Task.Delay メソッドは、指定時間後に終了する Task オブジェクトを生成します。The Task.Delay method produces a Task object that finishes after the specified time. このメソッドを使用すると、データのポーリングをときどき行うループをビルドしたり、タイムアウトを使用したり、ユーザー入力の処理を遅延させたりすることができます。You can use this method to build loops that occasionally poll for data, introduce time-outs, delay the handling of user input for a predetermined time, and so on.

Task(T).FromResultTask(T).FromResult

Task.FromResult メソッドを使用すると、あらかじめ計算された結果を保持する Task<TResult> オブジェクトを作成できます。By using the Task.FromResult method, you can create a Task<TResult> object that holds a pre-computed result. このメソッドは Task<TResult> オブジェクトの結果があらかじめ計算されている Task<TResult> オブジェクトを返す、非同期操作を実行する場合に便利です。This method is useful when you perform an asynchronous operation that returns a Task<TResult> object, and the result of that Task<TResult> object is already computed. キャッシュに保持されている非同期ダウンロード操作の結果を取得する FromResult の使用例の詳細については、「方法:事前計算済みのタスクを作成する」を参照してください。For an example that uses FromResult to retrieve the results of asynchronous download operations that are held in a cache, see How to: Create Pre-Computed Tasks.

タスクでの例外処理Handling exceptions in tasks

タスクで 1 つ以上の例外がスローされると、例外は AggregateException 例外でラップされます。When a task throws one or more exceptions, the exceptions are wrapped in an AggregateException exception. 例外はタスクに連結されたスレッドに反映されます。通常は、タスクの終了を待機しているスレッドか、または Result プロパティにアクセスするスレッドです。That exception is propagated back to the thread that joins with the task, which is typically the thread that is waiting for the task to finish or the thread that accesses the Result property. この動作では、.NET Framework ポリシーが適用され、既定ではすべてのハンドルされない例外によってプロセスが終了されます。This behavior serves to enforce the .NET Framework policy that all unhandled exceptions by default should terminate the process. 呼び出し元のコードは try/catch ブロックで、次のいずれかを使用して、例外を処理できます。The calling code can handle the exceptions by using any of the following in a try/catch block:

連結しているスレッドでも、タスクがガベージ コレクトされる前に Exception プロパティにアクセスすることで例外を処理できます。The joining thread can also handle exceptions by accessing the Exception property before the task is garbage-collected. このプロパティにアクセスすると、ハンドルされない例外が、オブジェクトが最終処理されたときにプロセスを終了する例外の反映動作をトリガーしないようにできます。By accessing this property, you prevent the unhandled exception from triggering the exception propagation behavior that terminates the process when the object is finalized.

例外とタスクの詳細については、例外処理に関する記事を参照してください。For more information about exceptions and tasks, see Exception Handling.

タスクの取り消しCanceling tasks

Task クラスは他の処理と連携したキャンセル処理をサポートしており、.NET Framework 4 で導入された System.Threading.CancellationTokenSource クラスおよび System.Threading.CancellationToken クラスと完全に統合されています。The Task class supports cooperative cancellation and is fully integrated with the System.Threading.CancellationTokenSource and System.Threading.CancellationToken classes, which were introduced in the .NET Framework 4. System.Threading.Tasks.Task クラスの多くのコンストラクターは、CancellationToken オブジェクトを入力パラメーターとして受け取ります。Many of the constructors in the System.Threading.Tasks.Task class take a CancellationToken object as an input parameter. StartNew および Run オーバーロードの多くも、CancellationToken パラメーターを含みます。Many of the StartNew and Run overloads also include a CancellationToken parameter.

CancellationTokenSource クラスを使用すると、トークンを作成し、後でキャンセル要求を発行できます。You can create the token, and issue the cancellation request at some later time, by using the CancellationTokenSource class. このトークンを Task に引数として渡し、同じトークンをキャンセル要求に応答するユーザー デリゲートで参照します。Pass the token to the Task as an argument, and also reference the same token in your user delegate, which does the work of responding to a cancellation request.

詳細については、「タスクのキャンセル」と「方法:タスクとその子を取り消す」を参照してください。For more information, see Task Cancellation and How to: Cancel a Task and Its Children.

TaskFactory クラスThe TaskFactory class

TaskFactory クラスには、タスクおよび継続タスクの作成と開始について、一般的なパターンをカプセル化する静的メソッドが用意されています。The TaskFactory class provides static methods that encapsulate some common patterns for creating and starting tasks and continuation tasks.

既定の TaskFactory へは、Task クラスまたは Task<TResult> クラス上の静的なプロパティとしてアクセスできます。The default TaskFactory can be accessed as a static property on the Task class or Task<TResult> class. TaskFactory を直接インスタンス化し、さまざまなオプションを指定することもできます。たとえば、CancellationTokenTaskCreationOptions オプション、TaskContinuationOptions オプション、TaskScheduler などです。You can also instantiate a TaskFactory directly and specify various options that include a CancellationToken, a TaskCreationOptions option, a TaskContinuationOptions option, or a TaskScheduler. タスク ファクトリを作成するときに指定されるオプションは、タスク ファクトリで作成したすべてのタスクに適用されます。ただし、TaskTaskCreationOptions 列挙型を使用して作成された場合は例外で、タスクのオプションによってタスク ファクトリのオプションがオーバーライドされます。Whatever options are specified when you create the task factory will be applied to all tasks that it creates, unless the Task is created by using the TaskCreationOptions enumeration, in which case the task's options override those of the task factory.

デリゲートなしのタスクTasks without delegates

Task を使用して、固有のユーザー デリゲートではなく外部コンポーネントによって実行される非同期操作をカプセル化する場合があります。In some cases, you may want to use a Task to encapsulate some asynchronous operation that is performed by an external component instead of your own user delegate. 操作が非同期プログラミング モデルの Begin/End パターンに基づいている場合、FromAsync メソッドを使用できます。If the operation is based on the Asynchronous Programming Model Begin/End pattern, you can use the FromAsync methods. そうでない場合は、TaskCompletionSource<TResult> オブジェクトを使用して、タスク内の操作をラップして、Task を外部からプログラミング可能にする利点を活用できます。たとえば、例外の反映および継続のサポートです。If that is not the case, you can use the TaskCompletionSource<TResult> object to wrap the operation in a task and thereby gain some of the benefits of Task programmability, for example, support for exception propagation and continuations. 詳細については、「TaskCompletionSource<TResult>」を参照してください。For more information, see TaskCompletionSource<TResult>.

カスタム スケジューラCustom schedulers

アプリケーションまたはライブラリのほとんどの開発者は、タスクを実行するプロセッサ、他のタスクと動作を同期する方法、System.Threading.ThreadPool でスケジュールする方法などについては気にしません。Most application or library developers do not care which processor the task runs on, how it synchronizes its work with other tasks, or how it is scheduled on the System.Threading.ThreadPool. 気にするのは、ホスト コンピューター上でできるだけ効率的に実行することだけです。They only require that it execute as efficiently as possible on the host computer. スケジュールの詳細についてより詳細に制御する必要がある場合、タスク並列ライブラリでは、既定のタスク スケジューラの設定を構成でき、さらにカスタム スケジューラを利用することもできます。If you require more fine-grained control over the scheduling details, the Task Parallel Library lets you configure some settings on the default task scheduler, and even lets you supply a custom scheduler. 詳細については、「TaskScheduler」を参照してください。For more information, see TaskScheduler.

TPL には、並列のシナリオおよび順次的なシナリオの両方に役立つ複数の新しいパブリック型があります。The TPL has several new public types that are useful in both parallel and sequential scenarios. これらの型には、System.Collections.Concurrent 名前空間における、スレッド セーフで、高速、スケーラブルなコレクション クラス、および新しい同期の型が含まれます。たとえば、System.Threading.Semaphore および System.Threading.ManualResetEventSlim は、特定の種類の作業負荷に関しては、先行タスクより効率的です。These include several thread-safe, fast and scalable collection classes in the System.Collections.Concurrent namespace, and several new synchronization types, for example, System.Threading.Semaphore and System.Threading.ManualResetEventSlim, which are more efficient than their predecessors for specific kinds of workloads. その他の .NET Framework 4 の新しい型には、System.Threading.BarrierSystem.Threading.SpinLock があり、以前のリリースでは利用できなかった機能が用意されています。Other new types in the .NET Framework 4, for example, System.Threading.Barrier and System.Threading.SpinLock, provide functionality that was not available in earlier releases. 詳細については、「Data Structures for Parallel Programming」を参照してください。For more information, see Data Structures for Parallel Programming.

カスタムのタスクの型Custom task types

System.Threading.Tasks.Task または System.Threading.Tasks.Task<TResult> から継承しないことをお勧めします。We recommend that you do not inherit from System.Threading.Tasks.Task or System.Threading.Tasks.Task<TResult>. 代わりに、AsyncState プロパティを使用して、追加のデータまたは状態を Task オブジェクトまたは Task<TResult> オブジェクトに関連付けることをおすすめします。Instead, we recommend that you use the AsyncState property to associate additional data or state with a Task or Task<TResult> object. 拡張メソッドを使用して、Task クラスおよび Task<TResult> クラスの機能を拡張することもできます。You can also use extension methods to extend the functionality of the Task and Task<TResult> classes. 拡張メソッドの詳細については、拡張メソッド (C# プログラミングガイド)拡張メソッド (Visual Basic) に関する記事を参照してください。For more information about extension methods, see Extension Methods and Extension Methods.

Task または Task<TResult> から継承する必要がある場合、RunRun、または System.Threading.Tasks.TaskFactory, System.Threading.Tasks.TaskFactory<TResult>、または System.Threading.Tasks.TaskCompletionSource<TResult> の各クラスを使用して、カスタムのタスクの型のインスタンスを作成することはできません。これらのクラスで作成されるのは、Task および Task<TResult> オブジェクトだけであるためです。If you must inherit from Task or Task<TResult>, you cannot use Run, Run, or the System.Threading.Tasks.TaskFactory, System.Threading.Tasks.TaskFactory<TResult>, or System.Threading.Tasks.TaskCompletionSource<TResult> classes to create instances of your custom task type because these mechanisms create only Task and Task<TResult> objects. また、TaskTask<TResult>TaskFactory、および TaskFactory<TResult> で提供されるタスク継続機構でも、Task オブジェクトと Task<TResult> オブジェクトしか作成されないため、これらの機構を使用してカスタムのタスクの型のインスタンスを作成することはできません。In addition, you cannot use the task continuation mechanisms that are provided by Task, Task<TResult>, TaskFactory, and TaskFactory<TResult> to create instances of your custom task type because these mechanisms also create only Task and Task<TResult> objects.

TitleTitle 説明Description
継続タスクを使用したタスクの連結Chaining Tasks by Using Continuation Tasks 継続の機能について説明します。Describes how continuations work.
アタッチされた子タスクとデタッチされた子タスクAttached and Detached Child Tasks アタッチされた子タスクとデタッチされた子タスクの違いについて説明します。Describes the difference between attached and detached child tasks.
タスクのキャンセルTask Cancellation Task オブジェクトに組み込まれているキャンセルのサポートについて説明します。Describes the cancellation support that is built into the Task object.
例外処理Exception Handling 同時実行スレッド上の例外を処理する方法について説明します。Describes how exceptions on concurrent threads are handled.
方法: Parallel.Invoke を使用して並列操作を実行するHow to: Use Parallel.Invoke to Execute Parallel Operations Invoke の使用方法について説明します。Describes how to use Invoke.
方法: タスクから値を返すHow to: Return a Value from a Task タスクから値を返す方法について説明します。Describes how to return values from tasks.
方法: タスクとその子を取り消すHow to: Cancel a Task and Its Children タスクを取り消す方法について説明します。Describes how to cancel tasks.
方法: 事前計算済みのタスクを作成するHow to: Create Pre-Computed Tasks キャッシュに保持されている非同期ダウンロード操作の結果を取得する Task.FromResult メソッドの使用例の詳細について説明します。Describes how to use the Task.FromResult method to retrieve the results of asynchronous download operations that are held in a cache.
方法: 並列タスクでバイナリ ツリーを走査するHow to: Traverse a Binary Tree with Parallel Tasks タスクを使用してバイナリ ツリーを走査する方法について説明します。Describes how to use tasks to traverse a binary tree.
方法: 入れ子のタスクのラップを解除するHow to: Unwrap a Nested Task Unwrap 拡張メソッドの使用方法を説明します。Demonstrates how to use the Unwrap extension method.
データの並列化Data Parallelism For および ForEach を使用してデータを対象に並列ループを作成する方法について説明しています。Describes how to use For and ForEach to create parallel loops over data.
並列プログラミングParallel Programming .NET Framework 並列プログラミングのトップ レベル ノード。Top level node for .NET Framework parallel programming.

関連項目See also