- •Introduction to the Parallel Extensions Library
- •Objectives
- •System Requirements
- •Exercises
- •Next Step:
- •Figure 2
- •Figure 4
- •Parallel.Invoke(Sub() WalkTree(node.Left), Sub() WalkTree(node.Right))
- •Figure 6
- •Next Step:
- •Parallel.Invoke(delegate { WalkTree(node.Left); }, delegate { WalkTree(node.Right); });
- •Visual Basic
- •Figure 7
- •Figure 11
- •Next Step:
- •Figure 12
- •Next Step:
- •Figure 13
- •Figure 14
- •Figure 16
- •Next Step:
Figure 7
Output from running several Tasks in parallel
Task 2 – Using the Wait() and WaitAll() Methods
The benefit of executing tasks in parallel is faster execution and the ability to leverage multi-core processors. However, you should also notice that the current implementation introduces the possibility the main application could exit before the thread processing the task finishes.
You can handle this possible situation by invoking the Wait() method on the individual Task objects. This causes the main thread to wait until the indicated tasks are complete before continuing on to the next instruction.
Replace the current method calls from Main(), with a call to Ex2Task2_WaitHandling(). This code will add wait handling to your example.
C#
static void Main(string[] args)
{
...
// Methods to call
Ex2Task2_WaitHandling();
...
}
Visual Basic
Sub Main(ByVal args() As String)
...
' Methods to call
Ex2Task2_WaitHandling()
...
End Sub
Add the Ex2Task2_WaitHandling() method to Program.cs (C#) or Module1.vb (Visual Basic):
(Code Snippet – Intro to Parallel Extensions Lab - Ex2 Ex2Task2_WaitHandling CSharp)
C#
private static void Ex2Task2_WaitHandling()
{
Task task1 = Task.Factory.StartNew(delegate
{ PayrollServices.GetPayrollDeduction(employeeData[0]); });
Task task2 = Task.Factory.StartNew(delegate
{ PayrollServices.GetPayrollDeduction(employeeData[1]); });
Task task3 = Task.Factory.StartNew(delegate
{ PayrollServices.GetPayrollDeduction(employeeData[2]); });
task1.Wait();
task2.Wait();
task3.Wait();
}
(Code Snippet – Intro to Parallel Extensions Lab - Ex2 Ex2Task2_WaitHandling VB)
C#
Private Sub Ex2Task2_WaitHandling()
Dim task1 As Task = Task.Factory.StartNew(Sub() PayrollServices.GetPayrollDeduction(employeeData(0)))
Dim task2 As Task = Task.Factory.StartNew(Sub() PayrollServices.GetPayrollDeduction(employeeData(1)))
Dim task3 As Task = Task.Factory.StartNew(Sub() PayrollServices.GetPayrollDeduction(employeeData(2)))
task1.Wait()
task2.Wait()
task3.Wait()
End Sub
Build and run the application.
You should observe that this time all three Tasks completed before the final time was reported, indicating the end of the main thread.
Figure 8
Output from running tasks in parallel with individual Wait() conditions
Note: The main thread waited for the created Task objects to complete before continuing operation. This approach is much simpler and cleaner than using ThreadPool.QueueUserWorkItem, which involves the creation and management of manual reset events, possible with the addition of Interlocked operations as well.
In addition to the Wait() method on the individual Task objects, the static Task class also offers a WaitAll() method allowing you to wait on a specified list of tasks with one call. To see this method in action, remove the individual calls to Wait() for task1, task2, and task3 and replace them with the following:
C#
static void Main(string[] args)
{
...
// Methods to call
Ex2Task2_WaitHandlingWaitAll();
...
}
Visual Basic
Sub Main(ByVal args() As String)
...
' Methods to call
Ex2Task2_WaitHandlingWaitAll()
...
End Sub
Add the Ex2Tas2_WaitHandlingWaitAll() method to Program.cs (C#) or Module1.vb (Visual Basic):
(Code Snippet – Intro to Parallel Extensions Lab - Ex2 Ex2Task2_WaitHandlingWaitAll CSharp)
C#
private static void Ex2Task2_WaitHandlingWaitAll()
{
Task task1 = Task.Factory.StartNew(delegate
{ PayrollServices.GetPayrollDeduction(employeeData[0]); });
Task task2 = Task.Factory.StartNew (delegate
{ PayrollServices.GetPayrollDeduction(employeeData[1]); });
Task task3 = Task.Factory.StartNew (delegate
{ PayrollServices.GetPayrollDeduction(employeeData[2]); });
Task.WaitAll(task1, task2, task3);
}
(Code Snippet – Intro to Parallel Extensions Lab - Ex2 Ex2Task2_WaitHandlingWaitAll VB)
Visual Basic
Private Sub Ex2Task2_WaitHandlingWaitAll()
Dim task1 As Task = Task.Factory.StartNew(Sub() PayrollServices.GetPayrollDeduction(employeeData(0)))
Dim task2 As Task = Task.Factory.StartNew(Sub() PayrollServices.GetPayrollDeduction(employeeData(1)))
Dim task3 As Task = Task.Factory.StartNew(Sub() PayrollServices.GetPayrollDeduction(employeeData(2)))
Task.WaitAll(task1, task2, task3)
End Sub
Build and run the application.
You should observe the main application waits until all individual Tasks are completed before continuing.
Figure 9
Output from running tasks in parallel with the WaitAll() method
Task 3 – Using the IsCompleted Property
There will be times when you want to check on the completion status of a Task before doing other work (for instance, you may have another task to run that is dependent on the first task completing first), but you may not want to utilize the Wait() method because Wait() blocks execution on the thread you’ve launched your Task from. For these situations, the Task class exposes an IsCompleted property. This enables you to check whether Task objects have completed their work before you continue with other processing.
Replace the current method calls from Main(), with a call to Ex2Task3_TaskIsCompleted().
C#
static void Main(string[] args)
{
...
// Methods to call
Ex2Task3_TaskIsCompleted();
...
}
Visual Basic
Sub Main(ByVal args() As String)
...
' Methods to call
Ex2Task3_TaskIsCompleted()
...
End Sub
Add the Ex2Task3_TaskIsCompleted() method to Program.cs (C#) or Module1.vb (Visual Basic):
(Code Snippet – Intro to Parallel Extensions Lab - Ex2 Ex2Task3_TaskIsCompleted CSharp)
C#
private static void Ex2Task3_TaskIsCompleted()
{
Task task1 = Task.Factory.StartNew(delegate
{ PayrollServices.GetPayrollDeduction(employeeData[0]); });
while (!task1.IsCompleted)
{
Thread.Sleep(1000);
Console.WriteLine("Waiting on task 1");
}
Task task2 = Task.Factory.StartNew(delegate
{ PayrollServices.GetPayrollDeduction(employeeData[1]); });
while (!task2.IsCompleted)
{
Thread.Sleep(1000);
Console.WriteLine("Waiting on task 2");
}
Task task3 = Task.Factory.StartNew(delegate
{ PayrollServices.GetPayrollDeduction(employeeData[2]); });
while (!task3.IsCompleted)
{
Thread.Sleep(1000);
Console.WriteLine("Waiting on task 3");
}
}
(Code Snippet – Intro to Parallel Extensions Lab - Ex2 Ex2Task3_TaskIsCompleted VB)
Visual Basic
Private Sub Ex2Task3_TaskIsCompleted()
Dim task1 As Task = Task.Factory.StartNew(Sub() PayrollServices.GetPayrollDeduction(employeeData(0)))
Do While Not task1.IsCompleted
Thread.Sleep(1000)
Console.WriteLine("Waiting on task 1")
Loop
Dim task2 As Task = Task.Factory.StartNew(Sub() PayrollServices.GetPayrollDeduction(employeeData(1)))
Do While Not task2.IsCompleted
Thread.Sleep(1000)
Console.WriteLine("Waiting on task 2")
Loop
Dim task3 As Task = Task.Factory.StartNew(Sub() PayrollServices.GetPayrollDeduction(employeeData(2)))
Do While Not task3.IsCompleted
Thread.Sleep(1000)
Console.WriteLine("Waiting on task 3")
Loop
End Sub
Build and run the application.
You should observe that Tasks two and three do not start until the previous Task’s IsCompleted property is true.
Figure 10
Output from running tasks in parallel and utilizing the IsCompleted property
Task 4 – Using the ContinueWith() Method
While the IsCompleted property is useful for polling a Task to see if it is finished in order to be able to fire off more work, the Task class offers an even more convenient option. Using the ContinueWith() method makes it easy to string tasks together to run in a specific order.
The functionality passed in as arguments to the ContinueWith() method will be executed once the Task object’s logic continues.
Replace the current method calls from Main(), with a call to Ex2Task4_ContinueWith().
C#
static void Main(string[] args)
{
...
// Methods to call
Ex2Task4_ContinueWith();
...
}
Visual Basic
Sub Main(ByVal args() As String)
...
' Methods to call
Ex2Task4_ContinueWith()
...
End Sub
Add the Ex2Task4_ContinueWith() method to Program.cs (C#) or Module1.vb (Visual Basic):
(Code Snippet – Intro to Parallel Extensions Lab - Ex2 Ex2Task4_ContinueWith CSharp)
C#
private static void Ex2Task4_ContinueWith()
{
Task task3 = Task.Factory.StartNew(delegate
{ PayrollServices.GetPayrollDeduction(employeeData[0]); })
.ContinueWith(delegate
{ PayrollServices.GetPayrollDeduction(employeeData[1]); })
.ContinueWith(delegate
{ PayrollServices.GetPayrollDeduction(employeeData[2]); });
task3.Wait();
}
(Code Snippet – Intro to Parallel Extensions Lab - Ex2 Ex2Task4_ContinueWith VB)
Visual Basic
Private Sub Ex2Task4_ContinueWith()
Dim task3 As Task = Task.Factory _
.StartNew(Sub() PayrollServices.GetPayrollDeduction(employeeData(0))) _
.ContinueWith(Sub() PayrollServices.GetPayrollDeduction(employeeData(1))) _
.ContinueWith(Sub() PayrollServices.GetPayrollDeduction(employeeData(2)))
task3.Wait()
End Sub
Note: Here you created the first Task as normal, but you used the ContinueWith() method to have the runtime execute the subsequent calls in order.
Build and run the application.
You should observe that the tasks execute in order – employee 1 first, followed by employee 2, and finally employee 3.
