Click here to Skip to main content
15,885,767 members
Articles / Programming Languages / C#
Tip/Trick

DependentTaskRunner - How to Run Tasks with Dependencies and Stay Sane

Rate me:
Please Sign up or sign in to vote.
5.00/5 (7 votes)
10 Jun 2017MIT2 min read 13K   75   4   5
Running tasks in parallel while taking into account the dependencies between them

Introduction

When you have multiple tasks to perform, it can really help if you can do some of them in parallel. However, when they are dependent on each other, it sometimes becomes a real pain to manage which tasks can be performed in parallel, and sometimes programmers prefer to give up and perform the tasks sequentially to avoid this pain. I didn't find any library that handles this problem, so I decided to write my own (DependentTaskRunner ) to make life a little bit easier. In this tip, I will explain how to use this library on a very simple example. The solution is pretty much scalable for more complex cases as well.

Using the Code

Open a new Visual Studio console application and add the DependentTaskRunner nuget package to it:

Image 1

Install It:

Image 2

In Program.cs file, add this using:

C++
using DependentTaskRunner;

Create a new class called MyTask:

C++
public class MyTask
{
    public MyTask[] Dependencies { get; set; }
    public Func<bool> Perform { get; set; }
}

Write the taskRunner initialization code in the Main function:

C++
var taskRunner = new TaskRunner<MyTask>(t => t.Dependencies, t => Task.Run(() => t.Perform()));

Now, we need to write the code that performs the tasks.

Suppose you want to perform 3 tasks: A, B, C.

C can be performed only after A and B are finished:

Image 3

Each task is represented as a function that returns a boolean value that indicates whether the task finished successfully or failed:

C++
private static bool RunA()
{
    Console.WriteLine(DateTime.Now + " A Started");
    Thread.Sleep(2000); // Perform some work...
    Console.WriteLine(DateTime.Now + " A Finished");
    return true;
}

private static bool RunB()
{
    Console.WriteLine(DateTime.Now + " B Started");
    Thread.Sleep(3000); // Perform some work...
    Console.WriteLine(DateTime.Now + " B Finished");
    return true;
}

private static bool RunC()
{
    Console.WriteLine(DateTime.Now + " C Started");
    Thread.Sleep(4000); // Perform some work...
    Console.WriteLine(DateTime.Now + " C Finished");
    return true;
}

Now we need to create the task objects in the Main function:

C++
var taskA = new MyTask { Perform = RunA };
var taskB = new MyTask { Perform = RunB };
var taskC = new MyTask { Dependencies = new[] { taskA, taskB }, Perform = RunC };

And make the tasks start running:

C++
taskRunner.PerformTasks(new[] { taskA, taskB, taskC });

And this is it.

Now we can run the code:

Image 4

We can see that A and B were performed in parallel and C is performed only after A and B are both finished.

The whole code should look like this now:

C++
class Program
{
    static void Main(string[] args)
    {
        var taskRunner = new TaskRunner<MyTask>
        (t => t.Dependencies, t => Task.Run(() => t.Perform()));

        var taskA = new MyTask { Perform = RunA };
        var taskB = new MyTask { Perform = RunB };
        var taskC = new MyTask { Dependencies = new[] { taskA, taskB }, Perform = RunC };

        taskRunner.PerformTasks(new[] { taskA, taskB, taskC });

        Console.ReadLine();
    }

    private static bool RunA()
    {
        Console.WriteLine(DateTime.Now + " A Started");
        Thread.Sleep(2000); // Perform some work...
        Console.WriteLine(DateTime.Now + " A Finished");
        return true;
    }

    private static bool RunB()
    {
        Console.WriteLine(DateTime.Now + " B Started");
        Thread.Sleep(3000); // Perform some work...
        Console.WriteLine(DateTime.Now + " B Finished");
        return true;
    }

    private static bool RunC()
    {
        Console.WriteLine(DateTime.Now + " C Started");
        Thread.Sleep(4000); // Perform some work...
        Console.WriteLine(DateTime.Now + " C Finished");
        return true;
    }

    public class MyTask
    {
        public MyTask[] Dependencies { get; set; }
        public Func<bool> Perform { get; set; }
    }
}

Pay attention that if a function of a task returns false, the tasks that depends on it will never be performed, for example if we will change the RunA function:

C++
private static bool RunA()
{
    Console.WriteLine(DateTime.Now + " A Started");
    Thread.Sleep(2000); // Perform some work...
    Console.WriteLine(DateTime.Now + " A Finished");
    return false;
}

This is the result we will get:

Image 5

The C Task is never performed because the A task failed.

I showed only one very basic way to use the library, if you would like to use Async/Await, you can find an example here. There are more examples to using the library here.

What's Next?

My code is actually open source and can be found here.

If you want some explanation about the code, I will be glad to write another article with explanation.

Feel free to write any suggestions or issues you have found.

Useful Links

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Israel Israel
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionReinventing the wheel ? Pin
delfo12-Jun-17 2:55
delfo12-Jun-17 2:55 
AnswerRe: Reinventing the wheel ? Pin
Alon Lek12-Jun-17 8:37
Alon Lek12-Jun-17 8:37 
GeneralRe: Reinventing the wheel ? Pin
delfo12-Jun-17 12:09
delfo12-Jun-17 12:09 
GeneralRe: Reinventing the wheel ? Pin
Alon Lek12-Jun-17 19:09
Alon Lek12-Jun-17 19:09 
GeneralMy vote of 5 Pin
Franc Morales10-Jun-17 12:46
Franc Morales10-Jun-17 12:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.