Prallelisation Talk Example – Tasks within Tasks

In this example I’m showing the launching of further tasks within an existing task.

The Main method launches a single task (of course, it would likely be many tasks in a real system) which is implemented by MainTask and then waits for that task to complete. The MainTask then launches many independent tasks (impelemnted as SubTask and attaches each of them to the parent task (in this case MainTask). This has the effect that when MainTask ends the code in Main is still blocked at the Wait call until all the child tasks have also completed.

Code Example

class Program
{
    static void Main(string[] args)
    {
        Task t = Task.Factory.StartNew(MainTask);
        t.Wait();

        Console.WriteLine("Program finished");
        Console.ReadLine();
    }

    public static void MainTask()
    {
        Console.WriteLine("Starting the Main Task");

        Task.Factory.StartNew(SubTask, TaskCreationOptions.AttachedToParent);
        Task.Factory.StartNew(SubTask, TaskCreationOptions.AttachedToParent);
        Task.Factory.StartNew(SubTask, TaskCreationOptions.AttachedToParent);
        Task.Factory.StartNew(SubTask, TaskCreationOptions.AttachedToParent);
        Task.Factory.StartNew(SubTask, TaskCreationOptions.AttachedToParent);
        Task.Factory.StartNew(SubTask, TaskCreationOptions.AttachedToParent);
        Task.Factory.StartNew(SubTask, TaskCreationOptions.AttachedToParent);
        Task.Factory.StartNew(SubTask, TaskCreationOptions.AttachedToParent);
        Task.Factory.StartNew(SubTask, TaskCreationOptions.AttachedToParent);
        Task.Factory.StartNew(SubTask, TaskCreationOptions.AttachedToParent);

        Console.WriteLine("Ending the Main Task");
    }

    public static void SubTask()
    {
        Console.WriteLine("Starting SubTask {0}", Task.CurrentId);
        Thread.Sleep(2500);
        Console.WriteLine("Ending SubTask {0}", Task.CurrentId);
    }
}

 

Output

Tasks within Tasks Example

Starting the Main Task
Ending the Main Task
Starting SubTask 1
Starting SubTask 2
Starting SubTask 3
Starting SubTask 4
Starting SubTask 5
Starting SubTask 6
Ending SubTask 2
Starting SubTask 7
Ending SubTask 1
Starting SubTask 8
Ending SubTask 3
Starting SubTask 9
Ending SubTask 4
Starting SubTask 10
Ending SubTask 5
Ending SubTask 6
Ending SubTask 7
Ending SubTask 8
Ending SubTask 9
Ending SubTask 10
Program finished

See also

I have also writtent a blog post on Tasks that create more work which may give further insight into this area.

Parallelisation Talk Example – Parallel.Invoke

Parallel.Invoke is the most basic way to start many tasks as the same time. The method takes as many Action<…> based delegates as needed. The Task Parallel Library takes care of the actual scheduling, degree of parallelism etc. Parallel.Invoke itself blocks until all the tasks have completed.

In this example there are two tasks that simply output numbers and letters to the console. One task takes slightly longer than the other. The output shows each task as it runs along with an indication of when it finishes, as well as the overall program finishes.

Code Example One

class Program
{
    static void Main(string[] args)
    {
        // Start two tasks in parallel
        Parallel.Invoke(TaskOne, TaskTwo);

        Console.WriteLine("Finished");
        Console.ReadLine();
    }

    // This task simple outputs the numbers 0 to 9
    private static void TaskOne()
    {
        for (int i = 0; i < 10; i++)
        {
            Console.WriteLine("TaskOne: {0}", i);
            Thread.Sleep(10);
        }
        Console.WriteLine("TaskOne Finished");
    }

    // This task simply outputs the letters A to K
    private static void TaskTwo()
    {
        for(char c = 'A'; c < 'K'; c++)
        {
            Console.WriteLine("TaskTwo: {0}", c);
            Thread.Sleep(5);
        }
        Console.WriteLine("TaskTwo Finished");
    }
}

Example output

Parallel.Invoke Example

TaskOne: 0
TaskTwo: A
TaskOne: 1
TaskTwo: B
TaskTwo: C
TaskTwo: D
TaskOne: 2
TaskTwo: E
TaskOne: 3
TaskTwo: F
TaskTwo: G
TaskTwo: H
TaskOne: 4
TaskTwo: I
TaskTwo: J
TaskOne: 5
TaskTwo Finished
TaskOne: 6
TaskOne: 7
TaskOne: 8
TaskOne: 9
TaskOne Finished
Finished

Code Example: Variation using Task.Factory.StartNew

The Parallel.Invoke method is equivalent setting up a number of tasks using Task.Factory.StartNew(…) then Task.WaitAll(…).

The following code example shows the same code (Main method only) but using Task.Factory.StartNew:

static void Main(string[] args)
{
    // Start two tasks in parallel
    Task t1 = Task.Factory.StartNew(TaskOne);
    Task t2 = Task.Factory.StartNew(TaskTwo);
    Task.WaitAll(t1, t2);

    Console.WriteLine("Finished");
    Console.ReadLine();
}