Görev tabanlı zaman uyumsuz programlama

Görev Paralel Kitaplığı (TPL), zaman uyumsuz bir işlemi temsil eden görev kavramını temel alır. Bazı açılardan, bir görev iş parçacığına veya ThreadPool iş öğesine benzer ancak daha yüksek bir soyutlama düzeyindedir. Görev paralelliği terimi, eşzamanlı olarak ç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, iş parçacığı sayısını belirleyen ve ayarlayan algoritmalarla geliştirilmiş olan öğesine kuyruğa ThreadPoolalınır. Bu algoritmalar, aktarım hızını en üst düzeye çıkarmak için yük dengeleme sağlar. Bu işlem görevleri nispeten basit hale getirir ve ayrıntılı paralelliği etkinleştirmek için bunların çoğunu 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.

Her iki nedenle de TPL, .NET'te çok iş parçacıklı, zaman uyumsuz ve paralel kod yazmak için tercih edilen API'dir.

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

yöntemi, Parallel.Invoke istediğiniz sayıda rastgele deyimi eşzamanlı olarak çalıştırmak için kullanışlı bir yol sağlar. Her iş öğesi için bir Action temsilci geçirmeniz yeter. 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, eşzamanlı olarak çalışan iki görev oluşturan ve başlatan temel Invoke bir çağrıyı gösterir. İlk görev adlı DoSomeWorkbir yöntemi çağıran bir lambda ifadesi ile temsil edilir ve ikinci görev adlı DoSomeOtherWorkbir yöntemi çağıran bir lambda ifadesi ile temsil edilir.

Not

TPL'de temsilciler tanımlamak için bu belgede lambda ifadeleri kullanılır. C# veya Visual Basic'teki lambda ifadelerini bilmiyorsanız bkz . PLINQ ve TPL'de Lambda İfadeleri.

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

Not

tarafından arka planda Invoke oluşturulan örnek sayısıTask, sağlanan temsilci sayısına eşit olmayabilir. TPL, özellikle çok sayıda temsilciyle çeşitli iyileştirmeler içerebilir.

Daha fazla bilgi için bkz . Nasıl yapılır: Paralel İşlemleri Yürütmek için Parallel.Invoke Kullanma.

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

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

Değer döndürmeyen bir görev sınıfı tarafından System.Threading.Tasks.Task temsil edilir. Değer döndüren bir görev, öğesinden Taskdevralan sınıfı tarafından System.Threading.Tasks.Task<TResult> temsil edilir. 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, bir görevin çalışmaya başladığını, tamamlandığını, iptal edilip edilmediğini veya özel durum oluşturup oluşturmadığını belirlemek için istediğiniz zaman görevin özelliğine erişebilirsiniz Status . Durum bir TaskStatus sabit listesiyle gösterilir.

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. Örnek, konsol modu uygulaması sona ermeden önce görevin yürütmeyi tamamladığınızdan emin olmak için yöntemine bir çağrı Task.Wait içerir.

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

public class Lambda
{
   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 as follows:
//       Hello from thread 'Main'.
//       Hello from taskA.
// or
//       Hello from taskA.
//       Hello from thread 'Main'.
Imports System.Threading

Namespace Lambda
    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.
End Namespace

Tek bir işlemde Task.Run görev oluşturmak ve başlatmak için de yöntemlerini kullanabilirsiniz. Görevi yönetmek için yöntemler, Run hangi görev zamanlayıcının geçerli iş parçacığıyla ilişkilendirildiğine bakılmaksızın varsayılan görev zamanlayıcısını kullanır. Bu Run yöntemler, görevin oluşturulması ve zamanlanması üzerinde daha fazla denetime ihtiyaç duyulmadığında görevleri oluşturmanın ve başlatmanın tercih edilen yoludur.

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

namespace Run;

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 as follows:
//       Hello from thread 'Main'.
//       Hello from taskA.
// or
//       Hello from taskA.
//       Hello from thread 'Main'.
Imports System.Threading

Namespace Run
    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.
End Namespace

Tek bir işlemde TaskFactory.StartNew görev oluşturmak ve başlatmak için yöntemini de kullanabilirsiniz. Aşağıdaki örnekte gösterildiği gibi aşağıdaki durumlarda bu yöntemi kullanabilirsiniz:

  • Oluşturma ve zamanlamanın ayrılması gerekmez ve ek görev oluşturma seçeneklerine veya belirli bir zamanlayıcının kullanılmasına ihtiyacınız vardır.

  • Görevine, özelliği aracılığıyla Task.AsyncState alabildiğiniz ek durum geçirmeniz gerekir.

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

namespace TaskIntro;

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

public class AsyncState
{
    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, ran on thread #3.
//     Task #1 created at 635116412924607584, ran on thread #4.
//     Task #2 created at 635116412924607584, ran on thread #4.
//     Task #3 created at 635116412924607584, ran on thread #4.
//     Task #4 created at 635116412924607584, ran on thread #3.
//     Task #5 created at 635116412924607584, ran on thread #3.
//     Task #6 created at 635116412924607584, ran on thread #4.
//     Task #7 created at 635116412924607584, ran on thread #4.
//     Task #8 created at 635116412924607584, ran on thread #3.
//     Task #9 created at 635116412924607584, ran on thread #4.
Imports System.Threading

Namespace AsyncState
    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 = Environment.CurrentManagedThreadId
                                                     End Sub,
                New CustomData With {.Name = i, .CreationTime = Date.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 635116412924597583, ran on thread #3.
    '     Task #1 created at 635116412924607584, ran on thread #4.
    '     Task #2 created at 635116412924607584, ran on thread #4.
    '     Task #3 created at 635116412924607584, ran on thread #4.
    '     Task #4 created at 635116412924607584, ran on thread #3.
    '     Task #5 created at 635116412924607584, ran on thread #3.
    '     Task #6 created at 635116412924607584, ran on thread #4.
    '     Task #7 created at 635116412924607584, ran on thread #4.
    '     Task #8 created at 635116412924607584, ran on thread #3.
    '     Task #9 created at 635116412924607584, ran on thread #4.
End Namespace

Taskve Task<TResult> her biri, yöntemini olarak Task.Factory.StartNew()çağırabilmeniz için varsayılan örneğini TaskFactorydöndüren bir statik Factory özellik sunar. Ayrıca, aşağıdaki örnekte görevler türünde System.Threading.Tasks.Task<TResult>olduğundan, her birinin hesaplamanın sonucunu içeren bir ortak Task<TResult>.Result özelliği vardır. Görevler zaman uyumsuz olarak çalışır ve herhangi bir sırada tamamlanabilir. Result Hesaplama tamamlanmadan önce özelliğine erişilirse, değer kullanılabilir olana kadar özelliği çağıran iş parçacığını engeller.

using System;
using System.Threading.Tasks;

public class Result
{
   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

Namespace Result
    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
End Namespace

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 sessize alma işleminden sonra değeri değil yalnızca değişkenin başvurularını yakalar. Aşağıdaki örnek, sorunu gösterir. Bir nesnenin örneğini CustomData oluşturan bir lambda ifadesine bir döngü sayacı geçirir ve nesnenin tanımlayıcısı olarak döngü sayacını kullanır. Örnekteki çıktıda gösterildiği gibi, her CustomData nesne aynı tanımlayıcıya sahiptir.

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

namespace Example.Iterations;

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

public class IterationTwo
{
   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

Namespace IterationsTwo
    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 = Date.Now.Ticks}
                                                         data.ThreadNum = Environment.CurrentManagedThreadId
                                                         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.
End Namespace

Oluşturucusu aracılığıyla göreve durum nesnesi döndürerek her yinelemede değere erişebilirsiniz. Aşağıdaki örnek, nesne oluşturulurken CustomData döngü sayacını kullanarak önceki örneği değiştirir ve bu da lambda ifadesine geçirilir. Örnekteki çıktıda gösterildiği gibi, artık her CustomData nesnenin örneği oluşturulduğu sırada döngü sayacının değerine göre benzersiz bir 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 IterationOne
{
   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

Namespace IterationsOne
    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 = Environment.CurrentManagedThreadId
                                                         Console.WriteLine("Task #{0} created at {1} on thread #{2}.",
                                                                         data.Name, data.CreationTime, data.ThreadNum)
                                                     End Sub,
                    New CustomData With {.Name = i, .CreationTime = Date.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.
End Namespace

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

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

namespace TaskIntro;

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

public class AsyncState
{
    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, ran on thread #3.
//     Task #1 created at 635116412924607584, ran on thread #4.
//     Task #2 created at 635116412924607584, ran on thread #4.
//     Task #3 created at 635116412924607584, ran on thread #4.
//     Task #4 created at 635116412924607584, ran on thread #3.
//     Task #5 created at 635116412924607584, ran on thread #3.
//     Task #6 created at 635116412924607584, ran on thread #4.
//     Task #7 created at 635116412924607584, ran on thread #4.
//     Task #8 created at 635116412924607584, ran on thread #3.
//     Task #9 created at 635116412924607584, ran on thread #4.
Imports System.Threading

Namespace AsyncState
    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 = Environment.CurrentManagedThreadId
                                                     End Sub,
                New CustomData With {.Name = i, .CreationTime = Date.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 635116412924597583, ran on thread #3.
    '     Task #1 created at 635116412924607584, ran on thread #4.
    '     Task #2 created at 635116412924607584, ran on thread #4.
    '     Task #3 created at 635116412924607584, ran on thread #4.
    '     Task #4 created at 635116412924607584, ran on thread #3.
    '     Task #5 created at 635116412924607584, ran on thread #3.
    '     Task #6 created at 635116412924607584, ran on thread #4.
    '     Task #7 created at 635116412924607584, ran on thread #4.
    '     Task #8 created at 635116412924607584, ran on thread #3.
    '     Task #9 created at 635116412924607584, ran on thread #4.
End Namespace

Görev Kimliği

Her görev, bir uygulama etki alanında benzersiz olarak tanımlayan bir tamsayı kimliği alır ve özelliği kullanılarak Task.Id erişilebilir. Kimlik, Visual Studio hata ayıklayıcısı Paralel Yığınlar ve Görevler pencerelerinde görev bilgilerini görüntülemek için kullanışlıdır. Kimlik, istekte bulunana kadar oluşturulmadığı anlamına gelir. Bu nedenle, program her çalıştırıldığında görevin kimliği farklı olabilir. Hata ayıklayıcıda görev kimliklerini görüntüleme 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örev oluşturan API'lerin çoğu parametre TaskCreationOptions kabul eden aşırı yüklemeler sağlar. Bu seçeneklerden birini veya daha fazlasını belirterek, görev zamanlayıcıya iş parçacığı havuzunda görevin nasıl zamanleneceğini bildirirsiniz. Seçenekler bit düzeyinde OR işlemi kullanılarak birleştirilebilir.

Aşağıdaki örnekte ve PreferFairness seçeneklerine LongRunning sahip bir görev gösterilmektedir:

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ığı, sırasıyla ve özellikleri tarafından tanımlanan ilişkili bir kültüre ve Thread.CurrentUICulture ui kültürüne Thread.CurrentCulture sahiptir. İş parçacığının kültürü biçimlendirme, ayrıştırma, sıralama ve dize karşılaştırma işlemleri gibi işlemlerde kullanılır. Kaynak aramada bir iş parçacığının kullanıcı arabirimi kültürü kullanılır.

Sistem kültürü, bir iş parçacığının varsayılan kültürünü ve kullanıcı arabirimi kültürünü tanımlar. Ancak ve özelliklerini kullanarak CultureInfo.DefaultThreadCurrentCultureCultureInfo.DefaultThreadCurrentUICulture bir uygulama etki alanındaki tüm iş parçacıkları için varsayılan bir kültür belirtebilirsiniz. Bir iş parçacığının kültürünü açıkça ayarlar ve yeni bir iş parçacığı başlatırsanız, yeni iş parçacığı çağıran iş parçacığının kültürünü devralamaz; bunun yerine, kültürü varsayılan sistem kültürüdür. Ancak görev tabanlı programlamada, görev farklı bir iş parçacığında zaman uyumsuz olarak çalıştırıldığında bile görevler ç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. Fransızca (Fransa) zaten geçerli kültürse İngilizce (Birleşik Devletler) olarak değişir. Ardından, yeni kültürde para birimi değerleri olarak biçimlendirilmiş bazı sayılar döndüren adlı formatDelegate bir temsilci çağırır. Temsilcinin bir görev tarafından zaman uyumlu veya zaman uyumsuz olarak çağrılması fark etmeksizin, 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'dan ö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, üzerinde çalıştığı iş parçacığının kültürüne göre belirlenir. Zaman uyumsuz görevler için, görev tarafından kullanılan kültür çağıran iş parçacığının kültüründen farklı olabilir.

Zaman uyumsuz görevler ve kültür hakkında daha fazla bilgi için makalenin "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

ve Task<TResult>.ContinueWith yöntemleri, Task.ContinueWith öncül görev tamamlandığında başlatılacak bir görev belirtmenize olanak sağlar. Devamlılık görevinin temsilcisine, öncül görevin durumunu inceleyebilmesi için öncül göreve bir başvuru geçirilir. Özelliğinin değerini Task<TResult>.Result alarak, devamlılık için giriş olarak öncül çıktısını kullanabilirsiniz.

Aşağıdaki örnekte, getData görev yöntemine TaskFactory.StartNew<TResult>(Func<TResult>) yapılan bir çağrıyla başlatılır. Görev processData tamamlandığında otomatik getData olarak başlatılır ve displayData tamamlandığında başlatılır processData . getData, görevin özelliği aracılığıyla getDataTask<TResult>.Result görev tarafından processData erişilebilen bir tamsayı dizisi oluşturur. Görev processData bu diziyi işler ve türü yöntemine Task<TResult>.ContinueWith<TNewResult>(Func<Task<TResult>,TNewResult>) geçirilen lambda ifadesinin dönüş türünden çıkarılmış bir sonuç döndürür. Görev displayData tamamlandığında otomatik processData olarak yürütülür ve Tuple<T1,T2,T3> lambda ifadesi tarafından processData döndürülen nesneye görevin Task<TResult>.Result özelliği aracılığıyla görev tarafından displayDataprocessData erişilebilir. Görev, displayData görevin sonucunu processData alır. Türü benzer şekilde çıkarılan ve özelliğindeki Result programın kullanımına sunulan bir sonuç üretir.

using System;
using System.Threading.Tasks;

public class ContinuationOne
{
   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

Namespace ContinuationsOne
    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
End Namespace

Bir Task.ContinueWith örnek yöntemi olduğundan, her bir öncül görev için bir Task<TResult> nesne örneği oluşturmak yerine yöntem çağrılarını birbirine zincirleyebilirsiniz. Aşağıdaki örnek, yönteme yapılan çağrıları birbirine bağlaması dışında işlevsel olarak öncekiyle Task.ContinueWith aynıdır. Task<TResult> Yöntem çağrıları zinciri tarafından döndürülen nesne, son devamlılık görevidir.

using System;
using System.Threading.Tasks;

public class ContinuationTwo
{
   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

Namespace ContinuationsTwo
    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
End Namespace

ContinueWhenAll ve ContinueWhenAny yöntemleri birden çok görevden devam etmenizi 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 seçeneği belirtmediğinde AttachedToParent , yeni görev üst görevle özel bir şekilde eşitlenmez. Bu eşitlenmemiş 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 örnekte, ayrılmış bir alt görev oluşturan bir görev gösterilmektedir:

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.

Not

Üst görev, ayrılmış alt görevin bitmesini beklemez.

Alt görevler oluşturma

Bir görevde çalışan kullanıcı kodu seçeneğiyle AttachedToParent bir görev oluşturduğunda, yeni görev üst görevin ekli alt görevi olarak bilinir. Üst görev tüm ekli alt görevlerin tamamlanmasını örtük olarak beklediğinden, yapılandırılmış görev paralelliğini ifade etmek için seçeneğini kullanabilirsiniz AttachedToParent . Aşağıdaki örnekte, 10 ekli alt görev oluşturan bir üst görev gösterilmektedir. Örnek, üst görevin tamamlanmasını beklemek için yöntemini çağırır Task.Wait . Ekli alt görevlerin tamamlanmasını açıkça beklemesi gerekmez.

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

public class Child
{
   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

Namespace Child
    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.
End Namespace

Üst görev, diğer görevlerin TaskCreationOptions.DenyChildAttach üst göreve eklenmesini önlemek için seçeneğini kullanabilir. Daha fazla bilgi için bkz . Ekli ve Ayrılmış Alt Görevler.

Görevlerin bitmek üzere olması bekleniyor

System.Threading.Tasks.Task ve System.Threading.Tasks.Task<TResult> türleri, bir görevin tamamlanmasını beklemenizi sağlayan yöntemlerin birkaç aşırı yüklemesini Task.Wait sağlar. Buna ek olarak, statik Task.WaitAll ve Task.WaitAny yöntemlerin aşırı yüklemeleri, bir görev dizisinin tamamlanmasını beklemenize olanak sağlar.

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ütülmesi tamamlanmadan sonlandırabilir. Örneğin, içindeki tüm zaman uyumlu kod Main (uygulama giriş noktası) yürütüldükten sonra konsol uygulamaları sonlandırılır.

Aşağıdaki örnekte özel durum işleme içermeyen temel desen gösterilmektedir:

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 İşleme.

Bazı aşırı yüklemeler bir zaman aşımı belirtmenize olanak tanır ve bazıları da beklemenin program aracılığıyla veya kullanıcı girişine yanıt olarak iptal edilebilmesi için giriş parametresi olarak ek CancellationToken bir parametre alır.

Bir görevi beklerken, bu görevin seçeneği kullanılarak TaskCreationOptions.AttachedToParent oluşturulan tüm alt öğelerini örtük olarak beklersiniz. Task.Wait görev zaten tamamlandıysa hemen döndürür. Yöntem Task.Wait , görev tamamlandıktan sonra çağrılsa Task.Wait bile bir görev tarafından tetiklenen özel durumları oluşturur.

Görevleri oluşturma

Task ve Task<TResult> sınıfları, birden çok görev oluşturmanıza yardımcı olacak çeşitli yöntemler sağlar. Bu yöntemler ortak desenler uygular ve C#, Visual Basic ve F# tarafından sağlanan zaman uyumsuz dil özelliklerini daha iyi kullanır. Bu bölümde , , WhenAnyDelayve FromResult yöntemleri açıklanmaktadırWhenAll.

Task.WhenAll

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

Task.WhenAny

Task.WhenAny yöntemi, birden çok Task veya Task<TResult> nesneden birinin bitmesini zaman uyumsuz olarak bekler. yönteminde Task.WhenAll olduğu gibi bu yöntem, tekdüzen olmayan görev kümelerini beklemenizi sağlayan aşırı yüklenmiş sürümler sağlar. WhenAny yöntemi özellikle aşağıdaki senaryolarda kullanışlıdır:

  • Yedekli işlemler: Birçok yolla gerçekleştirilebilecek bir algoritmayı veya işlemi göz önünde bulundurun. yöntemini kullanarak WhenAny önce biten işlemi seçebilir ve ardından kalan işlemleri iptal edebilirsiniz.

  • Araya eklenen işlemler: Bitirmesi gereken birden çok işlem başlatabilir ve her işlem tamamlandıkça sonuçları işlemek için yöntemini kullanabilirsiniz WhenAny . Bir işlem tamamlandıktan sonra bir veya daha fazla görevi başlatabilirsiniz.

  • Kısıtlanmış işlemler: Eşzamanlı işlem sayısını sınırlayarak önceki senaryoyu genişletmek için yöntemini kullanabilirsiniz WhenAny .

  • Süresi dolan işlemler: Yöntemi kullanarak WhenAny bir veya daha fazla görev ile belirli bir süreden sonra biten bir görev (örneğin, yöntemi tarafından Delay döndürülen bir görev) arasında seçim yapabilirsiniz. Delay yöntemi aşağıdaki bölümde açıklanmıştır.

Task.Delay

yöntemi, Task.Delay belirtilen süreden sonra biten bir Task nesne oluşturur. Verileri yoklayan döngüler oluşturmak, zaman aşımlarını belirtmek, kullanıcı girişinin işlenmesini geciktirmek vb. için bu yöntemi kullanabilirsiniz.

Task(T).FromResult

yöntemini kullanarak Task.FromResult , önceden hesaplanan sonucu tutan bir Task<TResult> nesne oluşturabilirsiniz. Bu yöntem, bir nesne döndüren zaman uyumsuz bir Task<TResult> işlem gerçekleştirdiğinizde ve bu Task<TResult> nesnenin sonucu zaten hesaplandığında kullanışlıdır. Önbellekte tutulan zaman uyumsuz indirme işlemlerinin sonuçlarını almak için kullanan FromResult bir örnek için bkz . Nasıl yapılır: Önceden Hesaplanan Görevler Oluşturma.

Görevlerdeki özel durumları işleme

Bir görev bir veya daha fazla özel durum oluşturursa, özel durumlar bir AggregateException özel duruma sarmalanmış olur. Bu özel durum, görevle birleştiren iş parçacığına geri yayılır. Genellikle, görevin tamam olmasını bekleyen iş parçacığı veya özelliğine erişen iş parçacığıdır Result . Bu davranış, varsayılan olarak işlenmeyen tüm özel durumların işlemi sonlandırması gereken .NET Framework ilkesini zorlar. Çağıran kod, bir try/catch blokta aşağıdakilerden birini kullanarak özel durumları işleyebilir:

Birleştiren iş parçacığı, görev çöp toplamadan önce özelliğine Exception 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 İşleme.

Görevleri iptal etme

sınıfı Task işbirliğine dayalı iptali destekler ve .NET Framework 4'te tanıtılan ve System.Threading.CancellationToken sınıfları ile System.Threading.CancellationTokenSource tam olarak tümleşiktir. Sınıfındaki oluşturucuların System.Threading.Tasks.Task çoğu bir CancellationToken nesneyi giriş parametresi olarak alır. StartNew ve Run aşırı yüklemelerinin çoğu bir CancellationToken parametre de içerir.

Belirteci oluşturabilir ve iptal isteğini daha sonra sınıfını CancellationTokenSource kullanarak düzenleyebilirsiniz. Belirteci bağımsız değişken olarak öğesine Task geçirin ve ayrıca bir iptal isteğine yanıt verme işini yapan kullanıcı temsilcinizde aynı belirteci referans edin.

Daha fazla bilgi için bkz . Görev İptali ve Nasıl yapılır: Görevi ve Alt Öğelerini İptal Etme.

TaskFactory sınıfı

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

Varsayılan TaskFactory değere, sınıfta veya Task<TResult> sınıfta statik bir özellik Task olarak erişilebilir. Ayrıca doğrudan bir TaskFactory örneği oluşturabilir ve bir seçeneği, TaskContinuationOptions bir TaskCreationOptions seçeneği veya TaskSchedulerseçeneğini CancellationTokeniçeren çeşitli seçenekler belirtebilirsiniz. Görev fabrikasını oluştururken belirtilen seçenekler, sabit listesi kullanılarak TaskCreationOptions oluşturulmadığı sürece Task oluşturduğu tüm görevlere uygulanır ve bu durumda görev seçenekleri görev fabrikasının seçeneklerini geçersiz kılar.

Temsilcisiz görevler

Bazı durumlarda, kullanıcı temsilciniz yerine bir dış bileşen tarafından gerçekleştirilen zaman uyumsuz bir işlemi kapsüllemek için kullanmak Task isteyebilirsiniz. İşlem Zaman Uyumsuz Programlama Modeli Başlangıç/Bitiş desenini temel alırsa, yöntemlerini kullanabilirsiniz FromAsync . Böyle bir durum söz konusu değilse, işlemi bir göreve sarmak ve böylece programlanabilirliğin avantajlarından Task bazılarını elde etmek için nesnesini kullanabilirsinizTaskCompletionSource<TResult>. Örneğin, özel durum yayma ve devamlılık desteği. Daha fazla bilgi için bkz. TaskCompletionSource<TResult>.

Özel zamanlayıcılar

Çoğu uygulama veya kitaplık geliştiricisi, görevin hangi işlemcide çalıştığını, çalışmasını diğer görevlerle nasıl eşitlediğinden veya üzerinde nasıl zamanlandığıyla System.Threading.ThreadPoolilgilenmez. Bunlar yalnızca ana bilgisayarda olabildiğince verimli çalışmasını gerektirir. Zamanlama ayrıntıları üzerinde daha ayrıntılı denetime ihtiyacınız varsa, TPL varsayılan görev zamanlayıcıda bazı ayarları yapılandırmanıza ve hatta özel bir zamanlayıcı sağlamanıza olanak tanır. Daha fazla bilgi için bkz. TaskScheduler.

TPL,paralel ve sıralı senaryolarda yararlı olan birkaç yeni genel türe sahiptir. Bunlar ad alanında birkaç iş parçacığı güvenli, hızlı ve ölçeklenebilir koleksiyon sınıfını System.Collections.Concurrent ve birkaç yeni eşitleme türünü içerir. Örneğin ve System.Threading.ManualResetEventSlim, System.Threading.Semaphore belirli iş yükleri için öncüllerinden daha verimlidir. .NET Framework 4'teki diğer yeni türler, örneğin System.Threading.Barrier ve System.Threading.SpinLock, önceki sürümlerde bulunmayan işlevler sağlar. Daha fazla bilgi için bkz . Paralel Programlama için Veri Yapıları.

Özel görev türleri

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

veya öğesinden Task devralmanız gerekiyorsa, özel görev türünüzün örneklerini oluşturmak için veya System.Threading.Tasks.TaskFactory, System.Threading.Tasks.TaskFactory<TResult>veya System.Threading.Tasks.TaskCompletionSource<TResult> sınıflarını kullanamazsınızRun.Task<TResult> Bu sınıflar yalnızca Task ve Task<TResult> nesneleri oluşturduğundan bunları kullanamazsınız. Ayrıca, özel görev türünüzün örneklerini oluşturmak için , Task<TResult>, TaskFactoryve TaskFactory<TResult> tarafından Tasksağlanan görev devamlılığı mekanizmalarını kullanamazsınız. Bu sınıflar yalnızca Task ve Task<TResult> nesneleri de oluşturduğundan bunları kullanamazsınız.

Ünvan 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 İptali nesnesinde yerleşik Task olarak bulunan iptal desteğini açıklar.
Ö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ı Invokeaçıklar.
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 Önbellekte Task.FromResult 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 Unwrap nasıl kullanılacağını gösterir.
Veri Paralelliği Verilerin üzerinde paralel döngülerin nasıl kullanılacağını For ve ForEach oluşturulacağını açıklar.
Paralel Programlama .NET Framework paralel programlama için üst düzey düğüm.

Ayrıca bkz.