Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Pustaka Paralel Tugas (TPL) didasarkan pada konsep tugas , yang mewakili operasi asinkron. Dalam beberapa cara, tugas menyerupai utas atau item kerja ThreadPool tetapi pada tingkat abstraksi yang lebih tinggi. Istilah paralelisme tugas mengacu pada satu atau beberapa tugas independen yang berjalan bersamaan. Tugas memberikan dua manfaat utama:
Penggunaan sumber daya sistem yang lebih efisien dan lebih dapat diskalakan.
Di balik layar, tugas-tugas diantrekan ke ThreadPool, yang telah diperkuat dengan algoritma yang memutuskan dan beradaptasi dengan jumlah utas. Algoritma ini memberikan penyeimbangan beban untuk memaksimalkan throughput. Proses ini membuat tugas relatif ringan, dan Anda dapat membuat banyak dari mereka untuk mengaktifkan paralelisme terperinci.
Kontrol yang lebih terprogram daripada yang dimungkinkan dengan utas atau item kerja.
Tugas dan kerangka kerja yang dibangun di sekitarnya menyediakan serangkaian API kaya yang mendukung penantian, pembatalan, kelanjutan, penanganan pengecualian yang kuat, status terperinci, penjadwalan kustom, dan banyak lagi.
Karena kedua alasan tersebut, TPL adalah API pilihan untuk menulis kode multi-utas, asinkron, dan paralel di .NET.
Membuat dan menjalankan tugas secara implisit
Metode Parallel.Invoke menyediakan cara mudah untuk menjalankan sejumlah pernyataan arbitrer secara bersamaan. Cukup masukkan delegasi Action untuk setiap item pekerjaan. Cara termudah untuk membuat delegat ini adalah dengan menggunakan ekspresi lambda. Ekspresi lambda dapat memanggil metode bernama atau memberikan kode sebaris. Contoh berikut menunjukkan panggilan Invoke dasar yang membuat dan memulai dua tugas yang berjalan secara bersamaan. Tugas pertama diwakili oleh ekspresi lambda yang memanggil metode bernama DoSomeWork, dan tugas kedua diwakili oleh ekspresi lambda yang memanggil metode bernama DoSomeOtherWork.
Nota
Dokumentasi ini menggunakan ekspresi lambda untuk menentukan delegasi dalam TPL. Jika Anda tidak terbiasa dengan ekspresi lambda di C# atau Visual Basic, lihat Ekspresi Lambda di PLINQ dan TPL.
Parallel.Invoke(() => DoSomeWork(), () => DoSomeOtherWork());
Parallel.Invoke(Sub() DoSomeWork(), Sub() DoSomeOtherWork())
Nota
Jumlah instans Task yang dibuat di belakang layar oleh Invoke belum tentu sama dengan jumlah delegasi yang disediakan. TPL mungkin menggunakan berbagai pengoptimalan, terutama dengan sejumlah besar delegasi.
Untuk informasi selengkapnya, lihat Cara: Menggunakan Parallel.Invoke untuk Menjalankan Operasi Paralel.
Untuk kontrol yang lebih besar atas eksekusi tugas atau mengembalikan nilai dari tugas, Anda harus bekerja dengan objek Task secara lebih eksplisit.
Membuat dan menjalankan tugas secara eksplisit
Tugas yang tidak mengembalikan nilai diwakili oleh kelas System.Threading.Tasks.Task. Tugas yang mengembalikan nilai diwakili oleh kelas System.Threading.Tasks.Task<TResult>, yang mewarisi dari Task. Objek tugas menangani detail infrastruktur dan menyediakan metode dan properti yang dapat diakses dari utas panggilan sepanjang masa pakai tugas. Misalnya, Anda dapat mengakses properti Status tugas kapan saja untuk menentukan apakah tugas tersebut telah mulai berjalan, berjalan hingga selesai, dibatalkan, atau telah memberikan pengecualian. Status diwakili oleh enumerasi TaskStatus.
Saat Anda membuat tugas, Anda memberikannya delegasi pengguna yang mengemas kode yang akan dijalankan oleh tugas tersebut. Delegasi dapat dinyatakan sebagai delegasi bernama, metode anonim, atau ekspresi lambda. Ekspresi Lambda dapat berisi panggilan ke metode bernama, seperti yang ditunjukkan dalam contoh berikut. Contohnya mencakup panggilan ke metode Task.Wait untuk memastikan bahwa tugas menyelesaikan eksekusi sebelum aplikasi mode konsol berakhir.
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
Anda juga dapat menggunakan metode Task.Run untuk membuat dan memulai tugas dalam satu operasi. Untuk mengelola tugas, metode Run menggunakan penjadwal tugas default, terlepas dari penjadwal tugas mana yang terkait dengan utas saat ini. Metode Run adalah cara yang lebih disukai untuk membuat dan memulai tugas ketika kontrol lebih atas pembuatan dan penjadwalan tugas tidak diperlukan.
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
Anda juga dapat menggunakan metode TaskFactory.StartNew untuk membuat dan memulai tugas dalam satu operasi. Seperti yang ditunjukkan dalam contoh berikut, Anda dapat menggunakan metode ini saat:
Pembuatan dan penjadwalan tidak perlu dipisahkan dan Anda memerlukan opsi pembuatan tugas tambahan atau penggunaan penjadwal tertentu.
Anda perlu meneruskan data status tambahan ke dalam tugas yang dapat Anda akses melalui properti Task.AsyncState.
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 dan Task<TResult> masing-masing mengekspos properti Factory statis yang mengembalikan instans default TaskFactory, sehingga Anda dapat memanggil metode sebagai Task.Factory.StartNew(). Selain itu, dalam contoh berikut, karena tugas berjenis System.Threading.Tasks.Task<TResult>, masing-masing memiliki properti Task<TResult>.Result publik yang berisi hasil komputasi. Tugas berjalan secara asinkron dan mungkin selesai dalam urutan apa pun. Jika properti Result diakses sebelum komputasi selesai, properti memblokir utas panggilan hingga nilai tersedia.
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
Untuk informasi selengkapnya, lihat Cara: Mengembalikan Nilai dari Tugas.
Saat Anda menggunakan ekspresi lambda untuk membuat delegasi, Anda memiliki akses ke semua variabel yang terlihat pada saat itu dalam kode sumber Anda. Namun, dalam beberapa kasus, terutama dalam perulangan, lambda tidak menangkap variabel seperti yang diharapkan. Ini hanya menangkap referensi variabel, bukan nilai, karena bermutasi setelah setiap iterasi. Contoh berikut mengilustrasikan masalahnya. Ini meneruskan penghitung perulangan ke ekspresi lambda yang menginstansiasi objek CustomData dan menggunakannya sebagai pengidentifikasi bagi objek tersebut. Seperti yang ditunjukkan oleh output dari contoh, setiap objek CustomData memiliki pengidentifikasi yang identik.
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
Anda dapat mengakses nilai pada setiap iterasi dengan menyediakan objek status ke tugas melalui konstruktornya. Contoh berikut memodifikasi contoh sebelumnya dengan menggunakan penghitung perulangan saat membuat objek CustomData, yang, pada gilirannya, diteruskan ke ekspresi lambda. Seperti yang ditunjukkan oleh output dari contoh, setiap objek CustomData sekarang memiliki pengidentifikasi unik berdasarkan nilai penghitung perulangan pada saat objek dibuat.
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
Status ini diteruskan sebagai argumen ke delegasi tugas, dan dapat diakses dari objek tugas dengan menggunakan properti Task.AsyncState. Contoh berikut adalah variasi pada contoh sebelumnya. Ini menggunakan properti AsyncState untuk menampilkan informasi tentang objek CustomData yang diteruskan ke ekspresi lambda.
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
ID Tugas
Setiap tugas menerima ID bilangan bulat yang secara unik mengidentifikasinya di domain aplikasi dan dapat diakses dengan menggunakan properti Task.Id. ID berguna untuk melihat informasi tugas di visual Studio debugger Parallel Stacks dan Tasks windows. ID dibuat secara malas, yang berarti ID tidak dibuat sampai diminta. Oleh karena itu, tugas mungkin memiliki ID yang berbeda setiap kali program dijalankan. Untuk informasi selengkapnya tentang cara menampilkan ID tugas di debugger, lihat Menggunakan Jendela Tugas dan Menggunakan Jendela Tumpukan Paralel.
Opsi pembuatan tugas
Sebagian besar API yang membuat tugas menyediakan kelebihan beban yang menerima parameter TaskCreationOptions. Dengan menentukan satu atau beberapa opsi ini, Anda memberi tahu penjadwal tugas tentang bagaimana menjadwalkan tugas pada kumpulan utas. Opsi mungkin dikombinasikan dengan menggunakan operasi bitwise ATAU.
Contoh berikut menunjukkan tugas yang memiliki opsi LongRunning dan PreferFairness:
var task3 = new Task(() => MyLongRunningMethod(),
TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness);
task3.Start();
Dim task3 = New Task(Sub() MyLongRunningMethod(),
TaskCreationOptions.LongRunning Or TaskCreationOptions.PreferFairness)
task3.Start()
Tugas, utas, dan budaya
Setiap utas memiliki budaya dan budaya antarmuka pengguna terkait, yang masing-masing didefinisikan oleh properti Thread.CurrentCulture dan Thread.CurrentUICulture. Kultur utas digunakan dalam operasi seperti pemformatan, penguraian, pengurutan, dan perbandingan string. Budaya UI utas digunakan dalam pencarian sumber daya.
Kultur sistem mendefinisikan kultur default dan kultur UI thread. Namun, Anda dapat menentukan budaya default untuk semua utas di domain aplikasi dengan menggunakan properti
Contoh berikut memberikan ilustrasi sederhana. Ini mengubah budaya aplikasi saat ini menjadi Bahasa Prancis (Prancis). Jika Bahasa Prancis (Prancis) sudah menjadi budaya saat ini, itu berubah menjadi Bahasa Inggris (Amerika Serikat). Kemudian memanggil delegasi bernama formatDelegate yang mengembalikan beberapa angka yang diformat sebagai nilai mata uang menurut kultur baru. Baik itu ketika delegasi dipanggil secara sinkron maupun asinkron oleh suatu tugas, tugas tersebut menggunakan konteks budaya dari utas pemanggil.
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 €
Nota
Dalam versi .NET Framework yang lebih lama dari .NET Framework 4.6, kultur tugas ditentukan oleh kultur dari utas tempat ia berjalan, bukan kultur dari utas pemanggil. Untuk tugas asinkron, kultur yang digunakan oleh tugas bisa berbeda dari kultur thread pemanggil.
Untuk informasi selengkapnya tentang tugas dan budaya asinkron, lihat bagian "Budaya dan operasi berbasis tugas asinkron" di artikel CultureInfo.
Membuat kelanjutan tugas
Metode Task.ContinueWith dan Task<TResult>.ContinueWith memungkinkan Anda menentukan tugas untuk dimulai ketika tugas antecedent selesai. Penghantaran tugas lanjutan diberikan referensi ke tugas sebelumnya untuk memeriksa statusnya. Dan dengan mengambil nilai properti Task<TResult>.Result, Anda dapat menggunakan output dari pendahulu sebagai input untuk kelanjutan.
Dalam contoh berikut, tugas getData dimulai dengan panggilan ke metode TaskFactory.StartNew<TResult>(Func<TResult>). Tugas processData dimulai secara otomatis saat getData selesai, dan displayData dimulai saat processData selesai.
getData menghasilkan array bilangan bulat, yang dapat diakses oleh tugas processData melalui properti getData dari tugas Task<TResult>.Result. Tugas processData memproses array tersebut dan mengembalikan hasil yang jenisnya disimpulkan dari jenis pengembalian ekspresi lambda yang diteruskan ke metode Task<TResult>.ContinueWith<TNewResult>(Func<Task<TResult>,TNewResult>). Tugas displayData dijalankan secara otomatis saat processData selesai, dan objek Tuple<T1,T2,T3> yang dikembalikan oleh ekspresi lambda processData dapat diakses oleh tugas displayData melalui properti processData tugas Task<TResult>.Result. Tugas displayData mengambil hasil tugas processData. Ini menghasilkan sebuah hasil yang jenisnya disimpulkan dengan cara yang serupa, dan yang tersedia pada program dalam properti Result.
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
Karena Task.ContinueWith adalah metode instans, Anda dapat menghubungkan panggilan metode bersama-sama alih-alih membuat instans objek Task<TResult> untuk setiap tugas sebelumnya. Contoh berikut secara fungsional identik dengan yang sebelumnya, kecuali bahwa ia menyatukan panggilan ke metode Task.ContinueWith. Objek Task<TResult> yang dikembalikan oleh rangkaian pemanggilan metode adalah tugas lanjutan terakhir.
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
Metode ContinueWhenAll dan ContinueWhenAny memungkinkan Anda melanjutkan dari beberapa tugas.
Untuk informasi selengkapnya, lihat Penyusunan Tugas menggunakan Tugas Lanjutan.
Membuat tugas anak yang terlepas
Saat kode pengguna yang berjalan dalam tugas membuat tugas baru dan tidak menentukan opsi AttachedToParent, tugas baru tidak disinkronkan dengan tugas induk dengan cara khusus apa pun. Jenis tugas yang tidak disinkronkan ini disebut tugas bersarang yang dilepas atau tugas anak yang dilepas . Contoh berikut menunjukkan tugas yang membuat satu tugas turunan yang mandiri:
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.
Nota
Tugas induk tidak menunggu tugas anak yang terpisah selesai.
Membuat tugas anak
Saat kode pengguna yang berjalan dalam suatu tugas membuat tugas dengan opsi AttachedToParent, tugas baru dikenal sebagai tugas turunan terlampir dari tugas induk. Anda dapat menggunakan opsi AttachedToParent untuk mengekspresikan paralelisme tugas terstruktur karena tugas induk secara implisit menunggu semua tugas anak terlampir selesai. Contoh berikut menunjukkan tugas induk yang membuat 10 tugas turunan terlampir. Contoh memanggil metode Task.Wait untuk menunggu tugas induk selesai. Tidak perlu secara eksplisit menunggu tugas turunan terlampir selesai.
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
Tugas induk dapat menggunakan opsi TaskCreationOptions.DenyChildAttach untuk mencegah tugas lain melampirkan ke tugas induk. Untuk informasi selengkapnya, lihat Tugas Anak yang Terlampir dan yang Tidak Terlampir.
Menunggu tugas selesai
Jenis System.Threading.Tasks.Task dan System.Threading.Tasks.Task<TResult> menyediakan beberapa kelebihan beban metode Task.Wait yang memungkinkan Anda menunggu tugas selesai. Selain itu, kelebihan beban metode Task.WaitAll statis dan Task.WaitAny memungkinkan Anda menunggu salah satu atau semua array tugas selesai.
Biasanya, Anda akan menunggu tugas karena salah satu alasan berikut:
Benang utama tergantung pada hasil akhir yang dihitung oleh sebuah tugas.
Anda harus menangani pengecualian yang mungkin dilemparkan dari tugas.
Aplikasi mungkin berakhir sebelum semua tugas selesai dieksekusi. Misalnya, aplikasi konsol akan berakhir setelah semua kode sinkron di
Main(titik masuk aplikasi) telah dijalankan.
Contoh berikut menunjukkan pola dasar yang tidak melibatkan penanganan pengecualian:
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...
Untuk contoh yang menunjukkan penanganan pengecualian, lihat Penanganan Pengecualian.
Beberapa kelebihan beban memungkinkan Anda menentukan waktu habis, dan yang lain mengambil CancellationToken tambahan sebagai parameter input sehingga penantian itu sendiri dapat dibatalkan baik secara terprogram atau sebagai respons terhadap input pengguna.
Saat Anda menunggu sebuah tugas, Anda secara implisit menunggu semua turunan dari tugas tersebut yang dibuat menggunakan opsi TaskCreationOptions.AttachedToParent. Task.Wait segera kembali jika tugas telah selesai. Metode Task.Wait melemparkan pengecualian apa pun yang dimunculkan oleh tugas, bahkan jika Task.Wait metode dipanggil setelah tugas selesai.
Merancang tugas
Kelas Task dan Task<TResult> menyediakan beberapa metode untuk membantu Anda menyusun beberapa tugas. Metode ini menerapkan pola umum dan memanfaatkan fitur bahasa asinkron yang lebih baik yang disediakan oleh C#, Visual Basic, dan F#. Bagian ini menjelaskan metode WhenAll, WhenAny, Delay, dan FromResult.
Task.WhenAll
Metode Task.WhenAll secara asinkron menunggu beberapa objek Task atau Task<TResult> selesai. Ini menyediakan versi kelebihan beban yang memungkinkan Anda menunggu serangkaian tugas yang tidak seragam. Misalnya, Anda dapat menunggu hingga beberapa objek Task dan Task<TResult> menyelesaikan tugasnya melalui satu panggilan metode.
Task.WhenAny
Metode Task.WhenAny secara asinkron menunggu salah satu dari beberapa objek Task atau Task<TResult> selesai. Seperti dalam metode Task.WhenAll, metode ini menyediakan versi kelebihan beban yang memungkinkan Anda menunggu serangkaian tugas yang tidak seragam. Metode WhenAny sangat berguna dalam skenario berikut:
operasi Redundan: Pertimbangkan algoritma atau operasi yang dapat dilakukan dalam banyak cara. Anda dapat menggunakan metode WhenAny untuk memilih operasi yang selesai terlebih dahulu lalu membatalkan operasi yang tersisa.
operasi bergantian: Anda dapat memulai beberapa operasi yang perlu diselesaikan dan menggunakan metode WhenAny untuk memproses hasil seiring setiap operasi selesai. Setelah satu operasi selesai, Anda dapat memulai satu atau beberapa tugas.
Operasi yang dibatasi: Anda dapat menggunakan metode WhenAny untuk memperluas skenario sebelumnya dengan membatasi jumlah operasi bersamaan.
Operasi kedaluwarsa: Anda dapat menggunakan metode WhenAny untuk memilih antara satu atau beberapa tugas dan tugas yang selesai pada waktu tertentu, misalnya, tugas yang dikembalikan oleh metode Delay. Metode Delay dijelaskan di bagian berikut.
Metode Task.Delay
Metode Task.Delay menghasilkan objek Task yang selesai setelah waktu yang ditentukan. Anda dapat menggunakan metode ini untuk membangun perulangan yang memeriksa data, untuk menetapkan batas waktu, untuk menunda penanganan input pengguna, dan sebagainya.
Tugas(T).DariHasil
Dengan menggunakan metode Task.FromResult, Anda dapat membuat objek Task<TResult> yang menyimpan hasil yang telah dihitung sebelumnya. Metode ini berguna ketika Anda melakukan operasi asinkron yang mengembalikan objek Task<TResult>, dan hasil dari objek Task<TResult> tersebut sudah dihitung. Untuk contoh yang menggunakan FromResult untuk mengambil hasil operasi pengunduhan asinkron yang disimpan dalam cache, lihat Cara: Membuat Tugas Pra-Komputasi.
Menangani pengecualian dalam tugas
Ketika tugas melemparkan satu atau beberapa pengecualian, pengecualian dibungkus dalam pengecualian AggregateException. Pengecualian tersebut disebarluaskan kembali ke utas yang bergabung dengan tugas. Biasanya, utas menunggu tugas selesai atau utas yang mengakses properti Result. Perilaku ini memberlakukan kebijakan .NET Framework bahwa semua pengecualian yang tidak tertangani secara default harus mengakhiri proses. Kode panggilan dapat menangani pengecualian dengan menggunakan salah satu hal berikut dalam blok try/catch:
Thread bergabung juga dapat mengatasi pengecualian dengan mengakses properti Exception sebelum tugas mengalami pengumpulan sampah. Dengan mengakses properti ini, Anda mencegah pengecualian yang tidak tertangani memicu perilaku penyebaran pengecualian yang mengakhiri proses ketika objek diselesaikan.
Untuk informasi selengkapnya tentang pengecualian dan tugas, lihat Penanganan Pengecualian.
Membatalkan tugas
Kelas Task mendukung pembatalan kooperatif dan sepenuhnya terintegrasi dengan kelas System.Threading.CancellationTokenSource dan System.Threading.CancellationToken, yang diperkenalkan dalam .NET Framework 4. Banyak konstruktor di kelas System.Threading.Tasks.Task mengambil objek CancellationToken sebagai parameter input. Banyak overload StartNew dan Run juga menyertakan parameter CancellationToken.
Anda dapat membuat token dan mengeluarkan permintaan pembatalan di lain waktu, dengan menggunakan kelas CancellationTokenSource. Berikan token ke Task sebagai argumen, dan juga referensikan token yang sama dalam delegasi pengguna, yang bertugas untuk merespons permintaan pembatalan.
Untuk informasi lebih lanjut, lihat Pembatalan Tugas dan Cara: Membatalkan Tugas dan Sub-tugasnya.
Kelas TaskFactory
Kelas TaskFactory menyediakan metode statis yang merangkum pola umum untuk membuat dan memulai tugas dan tugas kelanjutan.
Pola yang paling umum adalah StartNew, yang membuat dan memulai tugas dalam satu pernyataan.
Saat Anda membuat tugas kelanjutan dari beberapa antecedent, gunakan metode ContinueWhenAll atau metode ContinueWhenAny atau yang setara di kelas Task<TResult>. Untuk informasi selengkapnya, lihat Penyusunan Tugas menggunakan Tugas Lanjutan.
Untuk merangkum
BeginXModel Pemrograman Asinkron dan metodeEndXdalam instans Task atau Task<TResult>, gunakan metode FromAsync. Untuk informasi selengkapnya, lihat TPL dan Pemrograman Asinkron .NET Framework Tradisional.
TaskFactory default dapat diakses sebagai properti statis pada kelas Task atau kelas Task<TResult>. Anda juga dapat menginstansiasi TaskFactory secara langsung dan menentukan berbagai pilihan yang mencakup CancellationToken, pilihan TaskCreationOptions, pilihan TaskContinuationOptions, atau TaskScheduler. Opsi apapun yang Anda tentukan saat Anda membuat pabrik tugas akan diterapkan ke semua tugas yang dibuatnya kecuali Task dibuat dengan menggunakan TaskCreationOptions enumerasi, dalam hal ini opsi tugas akan menggantikan opsi dari pabrik tugas.
Tugas tanpa delegasi
Dalam beberapa kasus, Anda mungkin ingin menggunakan Task untuk merangkum beberapa operasi asinkron yang dilakukan oleh komponen eksternal alih-alih delegasi pengguna Anda. Jika operasi didasarkan pada pola Mulai/Akhir Model Pemrograman Asinkron, Anda dapat menggunakan metode FromAsync. Jika tidak demikian, Anda dapat menggunakan objek TaskCompletionSource<TResult> untuk membungkus operasi dalam sebuah tugas sehingga memperoleh beberapa manfaat dari pemrograman Task. Misalnya, dukungan untuk penyebaran dan kelanjutan proses pengecualian. Untuk informasi selengkapnya, lihat TaskCompletionSource<TResult>.
Penjadwal khusus
Sebagian besar pengembang aplikasi atau pustaka tidak peduli di prosesor mana tugas dijalankan, bagaimana tugas tersebut menyinkronkan pekerjaannya dengan tugas lain, atau bagaimana dijadwalkan pada System.Threading.ThreadPool. Mereka hanya mengharuskan dijalankan seefisien mungkin pada komputer host. Jika Anda memerlukan kontrol yang lebih halus atas detail penjadwalan, TPL memungkinkan Anda mengonfigurasi beberapa pengaturan pada penjadwal tugas default, dan bahkan memungkinkan Anda menyediakan penjadwal kustom. Untuk informasi selengkapnya, lihat TaskScheduler.
Struktur data terkait
TPL memiliki beberapa jenis publik baru yang berguna dalam skenario paralel dan berurutan. Ini termasuk beberapa kelas koleksi yang aman, cepat, dan dapat diskalakan di namespace System.Collections.Concurrent dan beberapa jenis sinkronisasi baru. Misalnya, System.Threading.Semaphore dan System.Threading.ManualResetEventSlim, yang lebih efisien daripada pendahulunya untuk jenis beban kerja tertentu. Jenis baru lainnya di .NET Framework 4, misalnya, System.Threading.Barrier dan System.Threading.SpinLock, menyediakan fungsionalitas yang tidak tersedia di rilis sebelumnya. Untuk informasi selengkapnya, lihat Struktur Data untuk Pemrograman Paralel.
Jenis tugas kustom
Kami menyarankan agar Anda tidak mewarisi dari System.Threading.Tasks.Task atau System.Threading.Tasks.Task<TResult>. Sebagai gantinya, kami sarankan Anda menggunakan properti AsyncState untuk mengaitkan data atau status tambahan dengan objek Task atau Task<TResult>. Anda juga dapat menggunakan metode ekstensi untuk memperluas fungsionalitas kelas Task dan Task<TResult>. Untuk informasi selengkapnya tentang metode ekstensi, lihat Metode Ekstensi dan Metode Ekstensi .
Jika Anda harus mewarisi dari Task atau Task<TResult>, Anda tidak dapat menggunakan kelas Run atau System.Threading.Tasks.TaskFactory, System.Threading.Tasks.TaskFactory<TResult>, atau System.Threading.Tasks.TaskCompletionSource<TResult> untuk membuat instans jenis tugas kustom Anda. Anda tidak dapat menggunakannya karena kelas ini hanya membuat objek Task dan Task<TResult>. Selain itu, Anda tidak dapat menggunakan mekanisme kelanjutan tugas yang disediakan oleh Task, Task<TResult>, TaskFactory, dan TaskFactory<TResult> untuk membuat instans jenis tugas kustom Anda. Anda tidak dapat menggunakannya karena kelas ini juga hanya membuat objek Task dan Task<TResult>.
Bagian terkait
| Titel | Deskripsi |
|---|---|
| Merangkai Tugas dengan Menggunakan Tugas Kelanjutan | Menjelaskan cara kerja kelanjutan. |
| Tugas Anak Terhubung dan Terpisah | Menjelaskan perbedaan antara tugas anak yang dilampirkan dan dilepas. |
| Pembatalan Tugas | Menjelaskan dukungan pembatalan yang disertakan dalam objek Task. |
| Penanganan Pengecualian | Menjelaskan bagaimana pengecualian pada thread yang berjalan bersamaan ditangani. |
| Cara: Menggunakan Parallel.Invoke untuk Menjalankan Operasi Paralel | Menjelaskan cara menggunakan Invoke. |
| Cara: Mengembalikan Sebuah Nilai dari Sebuah Tugas | Menjelaskan cara mengembalikan nilai dari tugas. |
| Cara: Membatalkan Tugas dan Anak-anaknya | Menjelaskan cara membatalkan tugas. |
| Cara: Membuat Tugas Pra-Komputasi | Menjelaskan cara menggunakan metode Task.FromResult untuk mengambil hasil operasi pengunduhan asinkron yang disimpan dalam cache. |
| Cara: Melintasi Pohon Biner dengan Tugas Paralel | Menjelaskan cara menggunakan tugas untuk melintasi pohon biner. |
| Cara: Membongkar Tugas Berlapis | Menunjukkan cara menggunakan metode ekstensi Unwrap. |
| Paralelisme Data | Menjelaskan cara menggunakan For dan ForEach untuk membuat perulangan paralel atas data. |
| Pemrograman Paralel | Simpul tingkat atas untuk pemrograman paralel pada .NET Framework. |