Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Görev Paralel Kitaplığı (TPL), zaman uyumsuz bir işlemi temsil eden görevkavramı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 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 ThreadPoolkuyruğa alı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.
İş parçacığı veya iş öğesiyle mümkün olandan daha fazla programatik kontrol.
Görevler ve bunların etrafında oluşturulan çerçeve, bekleme, iptal, devamlılık, güçlü ö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
Parallel.Invoke yöntemi, 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 aktarmanız yeterli. Bu temsilcileri oluşturmanın en kolay yolu lambda ifadelerini kullanmaktır. Lambda ifadesi adlandırılmış bir yöntemi çağırabilir veya kodu satır içi olarak sağlayabilir. Aşağıdaki örnekte, eşzamanlı olarak çalışan iki görev oluşturan ve başlatan temel bir Invoke çağrısı gösterilmektedir. İlk görev, DoSomeWork
adlı bir yöntemi çağıran bir lambda ifadesiyle temsil edilir ve ikinci görev DoSomeOtherWork
adlı bir yöntemi çağıran bir lambda ifadesiyle temsil edilir.
Not
Bu belgede, TPL'de temsilci tanımlamak için lambda ifadeleri kullanılır. C# veya Visual Basic'teki lambda ifadelerini bilmiyorsanız bkz. PLINQ ve TPL'deki Lambda İfadeleri.
Parallel.Invoke(() => DoSomeWork(), () => DoSomeOtherWork());
Parallel.Invoke(Sub() DoSomeWork(), Sub() DoSomeOtherWork())
Not
Task tarafından arka planda oluşturulan Invoke örneklerinin sayısı, 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 Task nesnelerle 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, System.Threading.Tasks.Task sınıfı tarafından temsil edilir. Değer döndüren bir görev, System.Threading.Tasks.Task<TResult>'den devralan Task sınıfıyla temsil edilir. Görev nesnesi, altyapı ayrıntılarını işler ve görevin ömrü boyunca çağıran iş parçacığından erişilebilen yöntemler ve özellikler sağlar. Örneğin, herhangi bir zamanda bir görevin Status özelliğine erişerek görevin çalışmaya başladığını, tamamlandığını, iptal edilip edilmediğini veya özel durum oluşturup oluşturmadığını belirleyebilirsiniz. Durum, bir TaskStatus numaralandırması ile gösterilir.
Bir 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, anonim 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 çağrı içerebilir. Örnek, konsol modu uygulaması sona ermeden önce görevin yürütülmesini tamamladığınızdan emin olmak için Task.Wait yöntemine bir çağrı 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 '{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
Ayrıca tek bir işlemde görev oluşturmak ve başlatmak için Task.Run yöntemlerini de kullanabilirsiniz. Görevi yönetmek için, Run yöntemleri, geçerli iş parçacığıyla hangi görev zamanlayıcının ilişkilendirildiğine bakılmaksızın varsayılan görev zamanlayıcısını kullanır. Run yöntemleri, 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 '{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 görev oluşturmak ve başlatmak için TaskFactory.StartNew 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öreve, Task.AsyncState özelliği aracılığıyla erişebileceğiniz ek bilgiyi aktarmanız 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
Task ve Task<TResult>'in her biri, yöntemi Factoryolarak çağırabilmeniz için varsayılan bir TaskFactoryörneğini döndüren statik bir Task.Factory.StartNew()
özelliğini kullanıma sunar. Ayrıca, aşağıdaki örnekte görevler System.Threading.Tasks.Task<TResult>türünde olduğundan, her birinin hesaplamanın sonucunu içeren bir genel Task<TResult>.Result özelliği vardır. Görevler zaman uyumsuz olarak çalışır ve herhangi bir sırada tamamlanabilir. hesaplama tamamlanmadan önce Result ö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($"{sum:N1}");
}
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: Bir Görevden Değer Döndürme.
Temsilci oluşturmak için lambda ifadesi kullandığınızda, kaynak kodunuzda o noktada görünen tüm değişkenlere erişebilirsiniz. Ancak, bazı durumlarda, özellikle döngüler içinde bir lambda değişkeni beklendiği gibi yakalamaz. Her yinelemeden sonra değişime uğradığı için değeri değil, yalnızca değişkenin başvurusunu yakalar. Aşağıdaki örnekte sorun gösterilmektedir. Bir CustomData
nesnesinin örneğini oluşturan bir lambda ifadesine 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
nesnesi 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 #{data.Name} created at {data.CreationTime} on thread #{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
Bir göreve oluşturucu aracılığıyla bir durum nesnesi sağlayarak her yinelemedeki değere erişebilirsiniz. Aşağıdaki örnek, lambda ifadesine geçirilen CustomData
nesnesi oluşturulurken döngü sayacını kullanarak önceki örneği değiştirir. Örnekteki çıktıda gösterildiği gibi, her CustomData
nesnesi artık nesnenin örneği oluşturulduğu sırada 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 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 #{data.Name} created at {data.CreationTime} on thread #{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 Task.AsyncState özelliği kullanılarak görev nesnesinden erişilebilir. Aşağıdaki örnek, önceki örnekteki bir çeşitlemedir. lambda ifadesine geçirilen AsyncState nesneleri hakkındaki bilgileri görüntülemek için CustomData
özelliğini kullanır.
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 Task.Id özelliği kullanılarak erişilebilir. Kimlik, Visual Studio hata ayıklayıcı Paralel Yığınlar ve Görevler pencerelerinde görev bilgilerini görüntülemek için kullanışlıdır. Kimlik, gecikmeli olarak oluşturulur, bu da istekte bulunulana 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, TaskCreationOptions parametresi 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 tabanlı VEYA işlemi kullanılarak birleştirilebilir.
Aşağıdaki örnekte, LongRunning ve PreferFairness seçeneklerine 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 Thread.CurrentCulture ve Thread.CurrentUICulture özellikleri tarafından tanımlanan ilişkili bir Kültüre ve UI Kültürüne sahiptir. İş parçacığının kültürü, biçimlendirme, ayrıştırma, sıralama ve dize karşılaştırma gibi işlemlerde kullanılır. Kaynak aramada iş parçacığının kullanıcı arabirim 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, CultureInfo.DefaultThreadCurrentCulture ve CultureInfo.DefaultThreadCurrentUICulture özelliklerini kullanarak 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) olacak şekilde değiştirir. Fransızca (Fransa) zaten geçerli kültürse İngilizce (ABD) olarak değişir. Ardından, yeni kültürde para birimi değerleri olarak biçimlendirilmiş bazı sayıları döndüren formatDelegate
adlı 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 {Thread.CurrentThread.ManagedThreadId}");
// Make the current culture different from the system culture.
Console.WriteLine($"The current culture is {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 {CultureInfo.CurrentCulture.Name}.\n");
// 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. Asenkron görevlerde, görevde 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 CultureInfo makalesindeki "Kültür ve zaman uyumsuz görev tabanlı işlemler" bölümüne bakın.
Görev devamlılıkları oluşturma
Task.ContinueWith ve Task<TResult>.ContinueWith yöntemleri, öncül görev tamamlandığında başlatılacak bir görev belirtmenize olanak sağlar. Devam görevinin yetkilisine, öncül görevin durumunu inceleyebilmesi için öncül göreve bir referans geçirilir. Task<TResult>.Result özelliğinin değerini alarak, önceki çıkışını devam için giriş olarak kullanabilirsiniz.
Aşağıdaki örnekte, getData
görevi TaskFactory.StartNew<TResult>(Func<TResult>) yöntemine yapılan bir çağrıyla başlatılır.
processData
görevi getData
tamamlandığında otomatik olarak başlatılır ve displayData
tamamlandığında processData
başlatılır.
getData
, processData
görevin getData
özelliği aracılığıyla Task<TResult>.Result görevin erişebildiği bir tamsayı dizisi oluşturur.
processData
görevi bu diziyi işler ve sonucu, Task<TResult>.ContinueWith<TNewResult>(Func<Task<TResult>,TNewResult>) yöntemine geçen lambda ifadesinin dönüş türünden türetilmiş bir türde döndürür.
displayData
tamamlandığında processData
görevi otomatik olarak yürütülür ve Tuple<T1,T2,T3> lambda ifadesi tarafından döndürülen processData
nesnesine displayData
görevin processData
özelliği aracılığıyla Task<TResult>.Result görev tarafından erişilebilir.
displayData
görevi, processData
görevinin sonucunu alır. Türü benzer şekilde çıkarılan ve Result özelliğinde 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
Task.ContinueWith bir örnek yöntemi olduğundan, her bir öncül görev için bir Task<TResult> nesnesi örneği oluşturmak yerine yöntem çağrılarını birbirine zincirleyebilirsiniz. Aşağıdaki örnek, Task.ContinueWith yöntemine çağrıları birbirine bağlaması dışında işlevsel olarak öncekiyle aynıdır. Yöntem çağrıları zinciri tarafından döndürülen Task<TResult> nesnesi 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.
Bağımsız alt görevler oluşturma
Bir görevde çalışan kullanıcı kodu yeni bir görev oluşturduğunda ve AttachedToParent seçeneğini belirtmediğinde, yeni görev üst görevle özel bir şekilde eşitlenmez. Bu senkronize edilmemiş görev türüne, bağımsız iç içe görev veya bağımsız alt görevdenir. Aşağıdaki örnekte, bağımsız 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
Ana görev, bağımsız alt görevin bitmesini beklemez.
Alt görevler oluşturulması
Bir görevde çalışan kullanıcı kodu AttachedToParent seçeneğiyle bir görev oluşturduğunda, yeni görev üst görevin ekli alt görev olarak bilinir. Ana görev, tüm ekli alt görevlerin tamamlanmasını otomatik olarak beklediğinden, yapılandırılmış görev paralelliğini ifade etmek için AttachedToParent seçeneğini kullanabilirsiniz. Aşağıdaki örnekte, 10 ilişkili alt görev oluşturan bir üst görev gösterilmektedir. Örnek, üst görevin tamamlanmasını beklemek için Task.Wait yöntemini çağırır. 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 #{x} completed.");
},
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 üst göreve eklenmesini önlemek için TaskCreationOptions.DenyChildAttach seçeneğini kullanabilir. Daha fazla bilgi için bkz. Ekli ve Ayrılmış Alt Görevler.
Görevlerin tamamlanmasını bekliyor
System.Threading.Tasks.Task ve System.Threading.Tasks.Task<TResult> türleri, bir görevin tamamlanmasını beklemenizi sağlayan Task.Wait yöntemlerinin çeşitli aşırı yüklemelerini sağlar. Buna ek olarak, statik Task.WaitAll ve Task.WaitAny yöntemlerine ait fazladan yüklemeler, bir dizi görevden herhangi birinin veya tümünün tamamlanmasını beklemenize olanak sağlar.
Genellikle, şu nedenlerden biri yüzünden bir görev beklerdiniz:
Ana iş parçacığı, bir görev tarafından hesaplanan son sonucta bağlıdır.
Görevden oluşabilecek özel durumları işlemeniz gerekir.
Uygulama, tüm görevlerin yürütülmesi tamamlanmadan sonlandırabilir. Örneğin, konsol uygulamaları
Main
'daki tüm zaman uyumlu kod (uygulama giriş noktası) yürütüldükten sonra 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 zaman aşımı belirtmenize olanak tanırken, diğerleri de giriş parametresi olarak ek bir CancellationToken alarak bekleme işleminin program aracılığıyla veya kullanıcı girişine yanıt olarak iptal edilebilmesini sağlar.
Bir görevi beklerken, TaskCreationOptions.AttachedToParent seçeneği kullanılarak oluşturulan bu görevin tüm alt görevlerini de örtük olarak beklersiniz. Görev zaten tamamlandıysa, Task.Wait hemen geri döner. Task.Wait yöntemi, görev tamamlandıktan sonra Task.Wait yöntemi çağrılsa bile görev tarafından tetiklenen özel durumları fırlatır.
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 WhenAll, WhenAny, Delayve FromResult yöntemleri açıklanmaktadır.
Task.WhenAll
Task.WhenAll yöntemi zaman uyumsuz olarak birden çok Task veya Task<TResult> nesnesinin bitmesini bekler. Tekdüzen olmayan görev kümelerini beklemenizi sağlayan aşırı yüklenmiş sürümler sağlar. Örneğin, birden çok Task ve Task<TResult> nesnelerinin bir yöntem çağrısından tamamlanmasını bekleyebilirsiniz.
Task.WhenAny
Task.WhenAny yöntemi zaman uyumsuz olarak birden çok Task veya Task<TResult> nesneden birinin bitmesini bekler. Task.WhenAll yönteminde 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. önce biten işlemi seçmek ve ardından kalan işlemleri iptal etmek için WhenAny yöntemini kullanabilirsiniz.
Araya eklenen işlemler: Her işlem tamamlandıkça sonuçları işlemek için bitirmesi gereken birden çok işlem başlatabilir ve WhenAny yöntemini kullanabilirsiniz. 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 WhenAny yöntemini kullanabilirsiniz.
Süresi dolmuş işlemler: WhenAny yöntemini kullanarak bir veya daha fazla görev ile belirli bir süre sonra biten bir görev (örneğin, Delay yöntemi tarafından 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
Task.Delay yöntemi, belirtilen süreden sonra biten bir Task nesnesi 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.
Görev(T).Sonuçtan
Task.FromResult yöntemini kullanarak, önceden hesaplanan sonucu tutan bir Task<TResult> nesnesi oluşturabilirsiniz. Bu yöntem, bir Task<TResult> nesnesi döndüren zaman uyumsuz bir işlem yaparken ve bu Task<TResult> nesnesinin sonucu önceden hesaplandığında oldukça kullanışlıdır. Önbellekte tutulan zaman uyumsuz indirme işlemlerinin sonuçlarını almak için FromResult kullanan 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 fırlatırsa, bu özel durumlar bir AggregateException özel durumu içinde sarmalanır. Bu istisna, görevle birleşen iş parçacığına geri yayılır. Genellikle, görevin tamam olmasını bekleyen iş parçacığı veya Result özelliğine erişen iş parçacığıdır. Bu davranış, varsayılan olarak işlenmemiş tüm özel durumların işlemi sonlandırması gerektiğini belirten .NET Framework politikası gerektirir. Çağıran kod, try
/catch
bloğunda aşağıdakilerden birini kullanarak özel durumları işleyebilir:
Katılan iş parçacığı, görev çöp toplama işlemi gerçekleşmeden önce Exception özelliğine erişerek özel durumları da işleyebilir. Bu özelliğe erişerek, işlenmeyen özel durumun nesne sonlandırıldığı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
Task sınıfı işbirliğine dayalı iptali destekler ve .NET Framework 4'te tanıtılan System.Threading.CancellationTokenSource ve System.Threading.CancellationToken sınıfları ile tam olarak tümleşiktir. System.Threading.Tasks.Task sınıfındaki oluşturucuların çoğu giriş parametresi olarak bir CancellationToken nesnesi alır. StartNew ve Run aşırı yüklemelerinin çoğu CancellationToken parametresi de içerir.
belirteci oluşturabilir ve iptal isteğini daha sonra CancellationTokenSource sınıfını kullanarak düzenleyebilirsiniz. Belirteci Task'ye bir parametre olarak geçirin ve iptal isteğine yanıt verme işini yapan kullanıcı temsilcinizde aynı belirteci de kullanın.
Daha fazla bilgi için bkz. Görev İptali ve Görevi ve Alt Öğelerini İptal Etme: Nasıl Yapılır.
TaskFactory sınıfı
TaskFactory sınıfı, görevleri ve devamlılık görevlerini oluşturmak ve başlatmak için ortak desenleri kapsülleyen statik yöntemler sağlar.
En yaygın desen, tek bir deyimde bir görev oluşturan ve başlatan StartNewdesendir.
Birden çok öncülden devamlılık görevleri oluşturduğunuzda, ContinueWhenAll yöntemini veya ContinueWhenAny yöntemini ya da Task<TResult> sınıfındaki eşdeğerlerini kullanın. Daha fazla bilgi için bkz. Devamlılık Görevlerini Kullanarak Görevleri Zincirleme.
BeginX
veyaEndX
bir örneğinde Asenkron Programlama Modeli Task ve Task<TResult> yöntemlerini kapsüllemek için FromAsync yöntemlerini kullanın. Daha fazla bilgi için bkz. TPL ve Geleneksel .NET Framework Zaman Uyumsuz Programlama.
Varsayılan TaskFactoryTask sınıfında veya Task<TResult> sınıfında statik özellik olarak erişilebilir. Ayrıca doğrudan bir TaskFactory örneği oluşturabilir ve CancellationToken, TaskCreationOptions seçeneği, TaskContinuationOptions seçeneği veya TaskScheduleriçeren çeşitli seçenekleri belirtebilirsiniz. Görev fabrikasını oluştururken belirtilen seçenekler, Task numaralandırması kullanılarak bir TaskCreationOptions oluşturulmadığı sürece, oluşturduğu tüm görevlere uygulanır; bu durumda, görevin kendi 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 bir Task'ı kullanmak isteyebilirsiniz. İşlem Zaman Uyumsuz Programlama Modeli Başlangıç/Bitiş desenini temel alırsa, FromAsync yöntemlerini kullanabilirsiniz. Böyle bir durum söz konusu değilse, TaskCompletionSource<TResult> nesnesini kullanarak işlemi bir göreve sarmalayabilir ve böylece Task programlamanın avantajlarından bazılarını elde edebilirsiniz. Ö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ığı, çalışmasını diğer görevlerle nasıl eşitlediği veya System.Threading.ThreadPoolüzerinde nasıl zamanlandığıyla ilgilenmez. Yalnızca konak bilgisayarda mümkün olduğunca verimli bir şekilde yürütülmesini 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.
İlgili veri yapıları
TPL,paralel ve sıralı senaryolarda yararlı olan birkaç yeni genel türe sahiptir. Bunlar, System.Collections.Concurrent ad alanında birkaç iş parçacığı güvenli, hızlı ve ölçeklenebilir koleksiyon sınıfının yanı sıra birkaç yeni senkronizasyon türünü içerir. Örneğin, belirli iş yükleri için öncüllerinden daha verimli olan System.Threading.Semaphore ve System.Threading.ManualResetEventSlim. .NET Framework 4'teki diğer yeni türler, örneğin, System.Threading.Barrier ve System.Threading.SpinLockönceki sürümlerde kullanılamamış işlevler sağlar. Daha fazla bilgi için Paralel Programlama İçin Veri Yapıları'nıinceleyin.
Özel görev türleri
System.Threading.Tasks.Task veya System.Threading.Tasks.Task<TResult>'den devralmamanızı tavsiye ederiz. Bunun yerine, ek verileri veya durumu bir AsyncState veya Task nesnesiyle ilişkilendirmek için Task<TResult> özelliğini kullanmanızı öneririz. Task ve Task<TResult> sınıflarının işlevselliğini 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.
Task veya Task<TResult>devralmak zorundaysanız, özel görev türünüzün örneklerini oluşturmak için Run veya System.Threading.Tasks.TaskFactory, System.Threading.Tasks.TaskFactory<TResult>veya System.Threading.Tasks.TaskCompletionSource<TResult> sınıflarını kullanamazsınız. 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, Task<TResult>, TaskFactoryve TaskFactory<TResult> tarafından sağ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.
İlgili bölümler
Başlık | Açıklama |
---|---|
Devam Görevlerini Kullanarak Görevleri Zincirleme | Devamlılıkların nasıl çalıştığını açıklar. |
Ekli ve Ayrılmış Alt Görevler | Ekli ve ayrılmış alt görevler arasındaki farkı açıklar. |
Görev İptali | Task nesnesinde yerleşik olarak bulunan iptal desteğini açıklar. |
Özel Durum İşleme | Eşzamanlı iş parçacıklarındaki özel durumların nasıl işleneceğini açıklar. |
Nasıl Yapılır: Paralel İşlemleri Yürütmek için Parallel.Invoke Kullanma | Invokenasıl kullanılacağını açıklar. |
Nasıl Yapılır: Bir Görevden Değer Döndürme | Görevlerden değerlerin nasıl geri döndürüleceğini açıklar. |
Nasıl Yapılır: Bir Görevi ve Alt Görevlerini İptal Etme | Görevlerin nasıl iptal edileceğini açıklar. |
Nasıl yapılır: Önceden Hesaplanan Görevler Oluşturma | Önbellekte tutulan zaman uyumsuz indirme işlemlerinin sonuçlarını almak için Task.FromResult yönteminin nasıl kullanılacağını açıklar. |
Nasıl Yapılır: Paralel Görevlerle İkili Ağaçtan Geçiş Yapma | İkili ağaçtan geçiş yapmak için görevlerin nasıl kullanılacağını açıklar. |
Nasıl Yapılır: İç İçe Bir Görevi Çözme | Unwrap uzantısı yönteminin nasıl kullanılacağını gösterir. |
Veri Paralelliği | Veriler üzerinde paralel döngüler oluşturmak için For ve ForEach nasıl kullanılacağını açıklar. |
paralel programlama | .NET Framework paralel programlama için üst düzey düğüm. |
Ayrıca bkz.
- paralel programlama
- .NET Core & .NET Standard ile Paralel Programlama için Örnekleri