Görev tabanlı zaman uyumsuz programlama

Görev paralel kitaplığı (TPL), zaman uyumsuz bir işlemi temsil eden bir görev kavramını temel alır. Bazı yollarla, bir görev bir iş parçacığına veya ThreadPool iş öğesine benzer, ancak daha yüksek bir soyutlama düzeyinde olur. Görev Paralelliği terimi aynı anda çalışan bir veya daha fazla bağımsız görevi ifade eder. Görevler iki adet birincil avantaj sağlar:

  • Sistem kaynaklarının daha verimli ve daha ölçeklenebilir kullanımı.

    Arka planda görevler, ThreadPool iş parçacığı sayısını belirleyen ve izleyen ve aktarım hızını en üst düzeye çıkarmak için Yük Dengeleme sağlayan algoritmalarla geliştirilmiş olan öğesine sıraya alınır. Bu, görevleri oldukça basit hale getirir ve hassas paralellik sağlamak için bunlardan çok sayıda oluşturabilirsiniz.

  • Bir iş parçacığı veya iş öğesi ile mümkün olandan daha programlı denetim.

    Görevler ve bunların etrafına yerleşik çatı, bekleme, iptal, devamlılık, sağlam özel durum işleme, ayrıntılı durum, özel zamanlama ve daha fazlasını destekleyen zengin bir API kümesi sağlar.

Bu nedenlerden her ikisi için de TPL, .NET 'te çok iş parçacıklı, zaman uyumsuz ve paralel kod yazmak için tercih edilen API 'dir.

Görevleri örtülü olarak oluşturma ve çalıştırma

Parallel.InvokeYöntemi, her türlü rastgele deyimi eşzamanlı olarak çalıştırmak için kullanışlı bir yol sağlar. ActionHer iş öğesi için bir temsilci geçirin. Lambda ifadelerini kullanmak, bu temsilcileri oluşturmanın en kolay yoludur. Lambda ifadesi adlandırılmış bir yöntemi çağırabilir veya satır içi kodu sağlayabilir. Aşağıdaki örnek, Invoke aynı anda çalışan iki görev oluşturan ve Başlatan temel bir çağrıyı gösterir. İlk görev adlı bir yöntemi çağıran bir lambda ifadesiyle temsil edilir DoSomeWork ve ikinci görev adlı bir yöntemi çağıran bir lambda ifadesiyle temsil edilir DoSomeOtherWork .

Not

TPL'de temsilciler tanımlamak için bu belgede lambda ifadeleri kullanılır. C# veya Visual Basic lambda ifadeleriyle ilgili bilgi sahibi değilseniz bkz. PLıNQ ve TPL Içindeki lambda ifadeleri.

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

Not

TaskTarafından arka planda oluşturulan örneklerin sayısı, Invoke sağlanmış olan temsilcilerin sayısına eşit değildir. TPL, özellikle çok sayıda temsilci bulunduğunda, çeşitli iyileştirmeler uygulayabilir.

Daha fazla bilgi için bkz. nasıl yapılır: paralel Işlemleri yürütmek Için Parallel. Invoke kullanma.

Görev yürütme üzerinde daha fazla denetim veya görevden bir değer döndürme için nesnelerle daha açık bir şekilde çalışmanız gerekir Task .

Görevleri açıkça oluşturma ve çalıştırma

Değer döndürmeyen bir görev, sınıfı tarafından temsil edilir System.Threading.Tasks.Task . Değeri döndüren bir görev System.Threading.Tasks.Task<TResult> , öğesinden devralan sınıf tarafından temsil edilir Task . Görev nesnesi altyapı ayrıntılarını işler ve çağrıyı yapan iş parçacığının görevin ömrü boyunca erişebildiği yöntemler ve özellikler sağlar. Örneğin, Status bir görevin özelliğine, çalışmaya başlayıp başlamadığına, tamamlanana kadar çalışıp çalışmadığını, iptal edildiğini veya bir özel durum oluşturdu. Durum, bir sabit listesi ile temsil edilir TaskStatus .

Görev oluşturduğunuzda, görevin yürüteceği kodu kapsülleyen bir kullanıcı temsilcisi verirsiniz. Temsilci adlandırılmış bir temsilci, adsız bir yöntem veya lambda ifadesi olarak ifade edilebilir. Lambda ifadeleri, aşağıdaki örnekte gösterildiği gibi adlandırılmış bir yönteme yapılan çağrıyı içerebilir. Örneğin, Task.Wait Konsol modu uygulaması bitmeden önce görevin yürütmeyi tamamlamasını sağlamak için yöntemine bir çağrı içerdiğine dikkat edin.

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.RunTek bir işlemde bir görevi oluşturmak ve başlatmak için yöntemlerini de kullanabilirsiniz. Görevi yönetmek için Run Yöntemler, geçerli iş parçacığıyla hangi görev çizelgeleyicinin ilişkili olduğuna bakılmaksızın varsayılan görev zamanlayıcısını kullanır. RunGörevin oluşturulması ve zamanlanması üzerinde daha fazla denetim yapmanız gerekmiyorsa, görevler oluşturmak ve başlatmak için tercih edilen yöntem, yöntemler için tercih edilen yoldur.

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.

Aynı zamanda bir TaskFactory.StartNew işlem içinde bir görevi oluşturmak ve başlatmak için yöntemini de kullanabilirsiniz. Oluşturma ve zamanlamanın ayrılması gerekmiyorsa ve ek görev oluşturma seçeneklerine veya belirli bir Zamanlayıcı kullanımına ihtiyacınız varsa ya da Task.AsyncState Aşağıdaki örnekte gösterildiği gibi, özelliği aracılığıyla alabileceğiniz göreve ek durum iletmeniz gerektiğinde bu yöntemi kullanın.

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 ve Task<TResult> her biri Factory varsayılan bir örneğini döndüren statik bir özellik sunar TaskFactory , böylece yöntemini olarak çağırabilirsiniz Task.Factory.StartNew() . Ayrıca, aşağıdaki örnekte, görevler türünde olduğundan System.Threading.Tasks.Task<TResult> , her birinin Task<TResult>.Result Hesaplama sonucunu içeren bir public özelliği vardır. Görevler zaman uyumsuz olarak çalışır ve herhangi bir sırada tamamlanabilir. ResultHesaplama tamamlanmadan önce özelliğe erişilirse, özelliği, değer kullanılabilir olana kadar çağıran iş parçacığını engeller.

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

Daha fazla bilgi için bkz. nasıl yapılır: görevden değer döndürme.

Temsilci oluşturmak için lambda ifadesini kullandığınızda, kaynak kodunuzun o noktasında görünür durumda olan tüm değişkenlere erişebilirsiniz. Ancak bazı durumlarda, çoğunlukla da döngülerde, bir lambda değişkeni beklenen şekilde yakalamaz. Her yinelemeden sonra oluşturduğu değeri değil, yalnızca son değeri yakalar. Aşağıdaki örnek, sorunu gösterir. Bir nesneyi örnekleyen CustomData ve döngü sayacını nesnenin tanımlayıcısı olarak kullanan bir lambda ifadesine döngü sayacı geçirir. Örneğin çıkışının gösterdiği gibi, her CustomData nesnenin aynı tanımlayıcısı vardır.

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.

Oluşturucusu aracılığıyla göreve durum nesnesi döndürerek her yinelemede değere erişebilirsiniz. Aşağıdaki örnek, nesnesi oluşturulurken döngü sayacını kullanarak önceki örneği değiştirir CustomData , bu, sırasıyla lambda ifadesine geçirilir. Örneğin çıkışının gösterdiği gibi, her bir CustomData nesne artık nesnenin örneği oluşturulduğu zaman döngü sayacının değerine göre benzersiz bir tanımlayıcıya sahiptir.

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.

Bu durum, görev temsilcisine bir bağımsız değişken olarak geçirilir ve özelliği kullanılarak görev nesnesinden erişilebilir Task.AsyncState . Aşağıdaki örnek, önceki örneğin bir çeşididir. AsyncStateLambda ifadesine geçirilen nesneler hakkındaki bilgileri göstermek için özelliğini kullanır CustomData .

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

Görev Kimliği

Her görev, kendisini bir uygulama etki alanında benzersiz bir şekilde tanımlayan bir tamsayı KIMLIĞI alır ve özelliği kullanılarak erişilebilir Task.Id . KIMLIK, Visual Studio hata ayıklayıcısı paralel yığınları ve Görevler Windows 'da görev bilgilerini görüntülemek için yararlıdır. Kimlik gecikmeli olarak oluşturulur, yani istenene kadar oluşturulmaz; bu nedenle, program her çalıştırıldığında bir görevin farklı bir kimliği olabilir. Görev kimliklerinin hata ayıklayıcıda nasıl görüntüleneceği hakkında daha fazla bilgi için, bkz. Görevler penceresini kullanma ve Paralel Yığınlar penceresini kullanma.

Görev oluşturma seçenekleri

Görevleri oluşturan çoğu API, bir parametreyi kabul eden aşırı yüklemeler sağlar TaskCreationOptions . Bu seçeneklerden birini veya daha fazlasını belirterek, Görev Zamanlayıcısına iş parçacığı havuzunda görevi nasıl zamanlayacağınızı söylemiş olursunuz. Seçenekler bit düzeyinde or işlemi kullanılarak birleştirilebilir.

Aşağıdaki örnek, ve seçeneklerine sahip bir görevi gösterir LongRunning PreferFairness .

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

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

Görevler, iş parçacıkları ve kültür

Her iş parçacığında, Thread.CurrentCulture sırasıyla ve özellikleri tarafından tanımlanan ilişkili bir kültür ve UI kültürü vardır Thread.CurrentUICulture . Bir iş parçacığının kültürü, bu gibi işlemlerde biçimlendirme, ayrıştırma, sıralama ve dize karşılaştırması gibi kullanılır. Bir iş parçacığının UI kültürü, kaynak aramasında kullanılır.

Ve özelliklerini kullanarak bir uygulama etki alanındaki tüm iş parçacıkları için varsayılan bir kültür belirtmediğiniz müddetçe CultureInfo.DefaultThreadCurrentCulture CultureInfo.DefaultThreadCurrentUICulture , bir iş parçacığının varsayılan kültürü ve UI kültürü sistem kültürü tarafından tanımlanır. Bir iş parçacığının kültürünü açık olarak ayarlayıp yeni bir iş parçacığı başlattığınızda, yeni iş parçacığı çağıran iş parçacığının kültürünü almaz; Bunun yerine, kültürü varsayılan sistem kültürüdür. Ancak, görev tabanlı programlamada görevler farklı bir iş parçacığında zaman uyumsuz olarak çalıştırılsa bile çağıran iş parçacığının kültürünü kullanır.

Aşağıdaki örnek basit bir çizim sağlar. Uygulamanın geçerli kültürünü Fransızca (Fransa) olarak değiştirir (veya Fransızca (Fransa) zaten geçerli kültürden Ingilizce (Birleşik Devletler)). Daha sonra formatDelegate Yeni kültürde para birimi değeri olarak biçimlendirilen bazı sayılar döndüren adlı bir temsilciyi çağırır. Temsilcinin bir görev tarafından zaman uyumlu veya zaman uyumsuz olarak çağrılması durumunda, görev çağıran iş parçacığının kültürünü kullanır.

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

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 €
Imports System.Globalization
Imports System.Threading

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 €

Not

.NET Framework 4,6 ' den önceki .NET Framework sürümlerinde, bir görevin kültürü, çağıran iş parçacığının kültürüne değil, çalıştığı iş parçacığının kültürüne göre belirlenir. Zaman uyumsuz görevler için bu, görev tarafından kullanılan kültürün çağıran iş parçacığının kültürüyle farklı olabileceği anlamına gelir.

Zaman uyumsuz görevler ve kültür hakkında daha fazla bilgi için, konusunun "Kültür ve zaman uyumsuz görev tabanlı işlemler" bölümüne bakın CultureInfo .

Görev devamlılıkları oluşturma

Task.ContinueWithVe Task<TResult>.ContinueWith yöntemleri, öncül görevi bittiğinde başlamak için bir görev belirtmenizi sağlar. Devamlılık görevinin temsilcisi öncül göreve bir başvuru geçirdiğinden, öncül görevin durumunu inceleyebilir ve özelliğinin değerini alarak, Task<TResult>.Result öncül 'un çıkışını devamlılık için giriş olarak kullanabilir.

Aşağıdaki örnekte, getData görev yöntemine bir çağrı ile başlatılır TaskFactory.StartNew<TResult>(Func<TResult>) . processDataGörev tamamlandığında otomatik olarak başlatılır getData ve displayData processData tamamlandığında başlatılır. getData görevin özelliği aracılığıyla görevle erişilebilen bir tamsayı dizisi üretir processData getData Task<TResult>.Result . processDataGörev bu diziyi işler ve türü, metoduna geçirilen lambda ifadesinin dönüş türünden çıkarılan bir sonuç döndürür Task<TResult>.ContinueWith<TNewResult>(Func<Task<TResult>,TNewResult>) . displayDataGörev tamamlandığında otomatik olarak yürütülür processData ve Tuple<T1,T2,T3> lambda ifadesinin döndürdüğü nesne görevin processData displayData özelliği aracılığıyla görev için erişilebilir olur processData Task<TResult>.Result . displayDataGörev, görevin sonucunu alır processData ve türü benzer bir şekilde çıkarılan ve özelliğindeki program için kullanılabilir hale getirilen bir sonuç üretir Result .

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.ContinueWithBir örnek yöntemi olduğundan, Task<TResult> her öncül görev için bir nesne oluşturmak yerine Yöntem çağrılarını birlikte zincirleyebilirsiniz. Aşağıdaki örnek, yönteme bir araya gelen çağrıları zincirden hariç olmak üzere önceki örnekle aynıdır Task.ContinueWith . Task<TResult>Yöntem çağrılarının zinciri tarafından döndürülen nesnenin son devamlılık görevi olduğunu unutmayın.

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

ContinueWhenAllVe ContinueWhenAny yöntemleri, birden çok görevden devam etmeyi sağlar.

Daha fazla bilgi için bkz. devamlılık görevlerini kullanarak görevleri zincirleme.

Ayrılmış alt görevler oluşturma

Bir görevde çalışan Kullanıcı kodu yeni bir görev oluşturduğunda ve bu seçeneği belirtmediği zaman AttachedToParent , yeni görev üst görevle herhangi bir özel şekilde eşitlenmez. Eşitlenmemiş bu görev türü, ayrılmış iç içe görev veya ayrılmış alt görev olarak adlandırılır. Aşağıdaki örnek, bağlantısı kesik bir tane alt görev oluşturan bir üst görevi gösterir.

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.

Üst görevin, ayrılmış alt görevin tamamlanmasını beklemediğine dikkat edin.

Alt görevler oluşturma

Bir görevde çalışan Kullanıcı kodu seçeneğiyle bir görev oluşturduğunda AttachedToParent , yeni görev üst görevin iliştirilmiş alt görevi olarak bilinir. AttachedToParentÜst görev örtük olarak tüm eklenen alt görevlerin bitmesini beklediği için yapılandırılmış görev paralelliğini ifade etmek için seçeneğini kullanabilirsiniz. Aşağıdaki örnek, on tane bağlı alt görev oluşturan bir üst görevi gösterir. Örnek, Task.Wait üst görevin bitmesini beklemek için yöntemini çağırırsa, eklenen alt görevlerin tamamlanmasını açıkça beklemek zorunda değildir.

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.

Üst görev, TaskCreationOptions.DenyChildAttach diğer görevlerin üst göreve iliştirmesini engellemek için seçeneğini kullanabilir. Daha fazla bilgi için bkz. ekli ve ayrılmış alt görevler.

Görevlerin bitmesi bekleniyor

System.Threading.Tasks.TaskVe System.Threading.Tasks.Task<TResult> türleri, Task.Wait bir görevin bitmesini beketmenize olanak sağlayan yöntemlerin birkaç aşırı yüklemesini sağlar. Ayrıca, statik ve yöntemlerin aşırı yüklemeleri Task.WaitAll , Task.WaitAny bir görev dizisinin herhangi birinin veya tümünün bitmesini beketmenize olanak tanır.

Genellikle, aşağıdaki nedenlerden biri için beklemeniz gerekir:

  • Ana iş parçacığı, bir göreve göre hesaplanan nihai sonuca bağlıdır.

  • Görevden oluşturulan özel durumları işlemeniz gerekir.

  • Uygulama, tüm görevlerin yürütmesi tamamlanmadan sonlanabilir. Örneğin, Main (uygulama giriş noktası) içindeki tüm zaman uyumlu kod yürütüldüğü anda konsol uygulamaları sonlandırılır.

Aşağıdaki örnek, özel durum işleme içermeyen temel düzeni gösterir.

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...

Özel durum işlemeyi gösteren bir örnek için bkz. özel durum işleme.

Bazı aşırı yüklemeler bir zaman aşımı belirtmenize izin verir ve diğer bir deyişle, bir CancellationToken giriş parametresi olarak diğerleri, bekleme süresi programlı bir şekilde veya kullanıcı girdisine yanıt olarak iptal edilebilir.

Bir görevi beklerken, bu görevin, seçeneği kullanılarak oluşturulan tüm alt öğelerini örtük olarak beklemiş olursunuz TaskCreationOptions.AttachedToParent . Task.Wait görev zaten tamamlanmışsa, hemen döndürür. Bir görev tarafından oluşturulan tüm özel durumlar Task.Wait , Task.Wait yöntemi görev tamamlandıktan sonra çağrılsa bile bir yöntemi tarafından oluşturulur.

Görevler oluşturuluyor

TaskVe Task<TResult> sınıfları, yaygın desenleri uygulamak ve C#, Visual Basic ve F # tarafından sağlanan zaman uyumsuz dil özelliklerini daha iyi kullanmak için birden fazla görev oluşturmanıza yardımcı olabilecek çeşitli yöntemler sağlar. Bu bölümde,, WhenAll WhenAny Delay ve FromResult yöntemleri açıklanmaktadır.

Task.WhenAll

Task.WhenAllYöntemi, birden fazla veya nesnesinin tamamlanmasını zaman uyumsuz Task olarak bekler Task<TResult> . Tek düzen olmayan görevler kümesini beklemenize olanak tanıyan aşırı yüklü sürümler sağlar. Örneğin, birden çok Task ve Task<TResult> nesnesinin bir yöntem çağrısından tamamlanmasını bekleyebilirsiniz.

Task.WhenAny

Task.WhenAnyYöntemi, birden fazla veya nesneden birinin tamamlanmasını zaman uyumsuz Task olarak bekler Task<TResult> . Yönteminde olduğu gibi Task.WhenAll Bu yöntem, Tekdüzen olmayan görev kümelerini beklemenizi sağlayan aşırı yüklenmiş sürümler sağlar. WhenAnyYöntemi, aşağıdaki senaryolarda özellikle yararlıdır.

  • Yedekli işlemler. Birçok şekilde gerçekleştirilen bir algoritma veya işlem düşünün. WhenAnyİlk olarak sona erme işlemini seçmek için yöntemini kullanabilir ve ardından kalan işlemleri iptal edebilirsiniz.

  • Dönüşümlü işlemler. Her işlem tamamlandığında birden çok işlem başlatabilir ve WhenAny her işlem bittiğinde sonuçları işlemek için yöntemini kullanmanız gerekir. Bir işlem tamamlandıktan sonra bir veya daha fazla ek görev başlatabilirsiniz.

  • Daraltılmış işlemler. WhenAnyYöntemi, eşzamanlı işlemlerin sayısını sınırlayarak önceki senaryoyu genişletmek için kullanabilirsiniz.

  • Süresi dolan işlemler. WhenAnyYöntemi, bir veya daha fazla görev arasında seçim yapmak için yöntemini ve yöntemi tarafından döndürülen bir görev gibi belirli bir zamandan sonra sona ererek geçen bir görevi kullanabilirsiniz Delay . DelayYöntemi aşağıdaki bölümde açıklanmıştır.

Task.Delay

Task.DelayYöntemi, Task belirtilen zamandan sonra bitiyor bir nesne oluşturur. Bazen verileri yoklayan, zaman aşımlarını tanıtan, belirli bir süre boyunca kullanıcı girişinin işlenmesini erteleyen, vb. işlemler yapan döngüler oluşturmak için bu yöntemi kullanabilirsiniz.

Task(T).FromResult

Task.FromResultYöntemini kullanarak, Task<TResult> önceden hesaplanmış sonucu tutan bir nesne oluşturabilirsiniz. Bu yöntem, bir nesne döndüren zaman uyumsuz bir işlem gerçekleştirirken ve bu Task<TResult> Task<TResult> nesnenin sonucu zaten hesaplanmışsa yararlıdır. FromResultBir önbellekte tutulan zaman uyumsuz indirme işlemlerinin sonuçlarını almak için kullanan bir örnek için bkz. nasıl yapılır: önceden hesaplanan görevler oluşturma.

Görevlerde özel durumları işleme

Bir görev bir veya daha fazla özel durum oluşturduğunda, özel durumlar bir AggregateException özel durumla sarmalanır. Bu özel durum, genellikle görevin bitmesi için bekleyen iş parçacığı veya özelliğe erişen iş parçacığı olan görevle birleştiren iş parçacığına geri yayılır Result . Bu davranış, tüm işlenmemiş özel durumların varsayılan olarak işlemi sonlandırması gerektiğini belirten .NET Framework ilkesini zorlamaya yarar. Çağıran kod, bir blokta aşağıdakilerden birini kullanarak özel durumları işleyebilir try / catch :

Katılım iş parçacığı, Exception görev atık toplanmadan önce özelliğe erişerek özel durumları da işleyebilir. Bu özelliğe erişerek, işlenmeyen özel durumun, nesne hazırlandığında işlemi sonlandıran özel durum yayma davranışını tetiklemesini engellersiniz.

Özel durumlar ve görevler hakkında daha fazla bilgi için bkz. özel durum işleme.

Görevleri iptal etme

TaskSınıfı birlikte iptalleri destekler ve System.Threading.CancellationTokenSource System.Threading.CancellationToken .NET Framework 4 ' te tanıtılan ve sınıflarıyla tamamen tümleşiktir. Sınıftaki oluşturucuların birçoğu System.Threading.Tasks.Task bir CancellationToken giriş parametresi olarak bir nesnesi alır. StartNewVe Run aşırı yüklemelerin birçoğu Ayrıca bir parametre içerir CancellationToken .

Belirtecini oluşturabilir ve daha sonra sınıfını kullanarak iptal isteğini daha sonra verebilirsiniz CancellationTokenSource . Belirteci Task bağımsız değişken olarak öğesine geçirin ve ayrıca, bir iptal isteğine yanıt verme işini sağlayan Kullanıcı temsilcinizdeki aynı belirtece başvurun.

Daha fazla bilgi için bkz. Görev iptali ve nasıl yapılır: bir görevi ve alt öğelerini iptal etme.

TaskFactory Sınıfı

TaskFactorySınıfı, görevler ve devamlılık görevleri oluşturmak ve başlatmak için bazı ortak desenleri kapsülleyen statik yöntemler sağlar.

Varsayılan TaskFactory olarak, Task sınıf veya sınıf üzerinde statik bir özellik olarak erişilebilir Task<TResult> . Ayrıca, doğrudan bir örnek oluşturabilir TaskFactory ve bir CancellationToken , bir seçenek, TaskCreationOptions TaskContinuationOptions seçenek veya içeren çeşitli seçenekler belirtebilirsiniz TaskScheduler . Görev fabrikasını oluştururken belirtilen her türlü seçenek, Task numaralandırma kullanılarak oluşturulmadığı takdirde, görev TaskCreationOptions seçeneklerinin görev fabrikasının özelliklerini geçersiz kılması durumunda, oluşturduğu tüm görevlere uygulanır.

Temsilcileri olmayan görevler

Bazı durumlarda, Task kendi Kullanıcı temsilciniz yerine bir dış bileşen tarafından gerçekleştirilen bazı zaman uyumsuz işlemleri kapsüllemek için bir kullanmak isteyebilirsiniz. İşlem zaman uyumsuz programlama modeli başlangıç/bitiş düzenine dayanıyorsa, FromAsync yöntemlerini kullanabilirsiniz. Böyle bir durum söz konusu değilse, TaskCompletionSource<TResult> bir görevde işlemi kaydırmak için nesnesini kullanabilir ve bu sayede, Task özel durum yayma ve devamlılık desteği gibi programlama avantajlarından bazılarını elde edebilirsiniz. Daha fazla bilgi için bkz. TaskCompletionSource<TResult>.

Özel zamanlayıcılar

Çoğu uygulama veya kitaplık geliştiricisi, görevin hangi işlemci üzerinde çalıştığını, çalışmasını diğer görevlerle nasıl eşitleyeceğini veya üzerinde nasıl zamanlandığını önemsemez System.Threading.ThreadPool . Bunlar yalnızca ana bilgisayarda olabildiğince verimli çalışmasını gerektirir. Zamanlama ayrıntıları üzerinde daha hassas bir denetim gerekiyorsa, Görev Paralel Kitaplığı varsayılan görev zamanlayıcı üzerinde bazı ayarları yapılandırmanıza ve hatta özel bir zamanlayıcı girmenize olanak tanır. Daha fazla bilgi için bkz. TaskScheduler.

TPL'de, hem paralel hem de sıralı senaryolarda yararlı olan çeşitli, yeni genel türler vardır. Bunlar, ad alanında çok sayıda iş parçacığı açısından güvenli, hızlı ve ölçeklenebilir koleksiyon sınıfları System.Collections.Concurrent ve örneğin System.Threading.Semaphore ve System.Threading.ManualResetEventSlim belirli iş yükü türleri için öncüllerinden daha verimli olan birkaç yeni eşitleme türü içerir. .NET Framework 4 ' deki diğer yeni türler, örneğin ve, System.Threading.Barrier System.Threading.SpinLock önceki sürümlerde kullanılamayan işlevselliği sağlar. Daha fazla bilgi için bkz. paralel programlama Için veri yapıları.

Özel görev türleri

Veya ' den devralma yapmanızı öneririz System.Threading.Tasks.Task System.Threading.Tasks.Task<TResult> . Bunun yerine, AsyncState ek verileri veya durumu bir veya nesnesiyle ilişkilendirmek için özelliğini kullanmanızı öneririz Task Task<TResult> . Ve sınıflarının işlevlerini genişletmek için uzantı yöntemlerini de kullanabilirsiniz Task Task<TResult> . Uzantı yöntemleri hakkında daha fazla bilgi için bkz. Uzantı yöntemleri ve genişletme yöntemleri.

Veya ' den ' i veya ' den devralma yapmanız gerekiyorsa, Task Task<TResult> Run System.Threading.Tasks.TaskFactory System.Threading.Tasks.TaskFactory<TResult> System.Threading.Tasks.TaskCompletionSource<TResult> Bu mekanizmalar yalnızca ve nesneleri oluşturduğundan özel görev tipinizi oluşturmak için, Task veya, ya da sınıflarını kullanamazsınız Task<TResult> . Bunlara ek olarak,,,, ve tarafından sunulan görev devamlılık mekanizmalarını Task ,,, Task<TResult> ve tarafından TaskFactory TaskFactory<TResult> özel görev türü örnekleri oluşturmak için kullanamazsınız, çünkü bu mekanizmalar yalnızca Task ve nesnelerini de oluşturur Task<TResult> .

Başlık Açıklama
Devamlılık Görevlerini Kullanarak Görevleri Birbirine Bağlama Devamlılıkların nasıl çalıştığını açıklar.
Eklenen ve Ayrılan Alt Görevler Ekli ve ayrılmış alt görevler arasındaki farkı açıklar.
Görev iptali Nesnesinde yerleşik olan iptal desteğini açıklar Task .
Özel Durum İşleme Eşzamanlı iş parçacıklarındaki özel durumların nasıl işlendiğini açıklar.
Nasıl yapılır: Paralel İşlemleri Yürütmek için parallel_invoke Kullanma ' Nin nasıl kullanılacağını açıklar Invoke .
Nasıl yapılır: Bir Görevden Değer Döndürme Değerlerin görevlerden nasıl döndürüleceğini açıklar.
Nasıl yapılır: Bir Görevi ve Alt Öğelerini İptal Etme Görevlerin nasıl iptal edildiğini açıklar.
Nasıl yapılır: Önceden Hesaplanan Görevler Oluşturma Task.FromResultBir önbellekte tutulan zaman uyumsuz indirme işlemlerinin sonuçlarını almak için yönteminin nasıl kullanılacağını açıklar.
Nasıl yapılır: Paralel Görevler İçeren Bir İkili Ağacı Gezme İkili ağacı geçirmek için görevlerin nasıl kullanılacağını açıklar.
Nasıl yapılır: İç İçe Geçmiş Bir Görevi Sarmalamadan Çıkarma Uzantı yönteminin nasıl kullanılacağını gösterir Unwrap .
Veri paralelliği For ForEach Verilerin üzerinde paralel döngüler oluşturmayı ve kullanmayı açıklar.
Paralel programlama .NET Framework paralel programlama için üst düzey düğüm.

Ayrıca bkz.