Cookbook » Prioritized Tasking

This chapter demonstrates how to assigns a task a priority to hint the scheduler about one task of a higher priority should start earlier than another task of a lower priority. Task priorities are useful in many cases. For instance, we may prioritize some tasks over others to improve responsiveness or data locality of parallel tasks.

Assign a Priority to a Task

Taskflow supports three different priority levels, tf::TaskPriority::HIGH, tf::TaskPriority::NORMAL, and tf::TaskPriority::LOW, as defined in tf::TaskPriority. When there are parallel tasks (i.e., no dependencies), Taskflow will try to execute tasks of higher priorities before tasks of lower priorities. By default, all tasks have the highest priorities (tf::TaskPriority::HIGH) unless otherwise assigned.

tf::Executor executor(1);
tf::Taskflow taskflow;

int counter = 0;

auto [A, B, C, D, E] = taskflow.emplace(
  [] () { },
  [&] () { 
    std::cout << "Task B: " << counter++ << '\n';  // 0
  },
  [&] () { 
    std::cout << "Task C: " << counter++ << '\n';  // 2
  },
  [&] () { 
    std::cout << "Task D: " << counter++ << '\n';  // 1
  },
  [] () { }
);

A.precede(B, C, D); 
E.succeed(B, C, D);

B.priority(tf::TaskPriority::HIGH);
C.priority(tf::TaskPriority::LOW);
D.priority(tf::TaskPriority::NORMAL);

executor.run(taskflow).wait();

In the above code, we have a task graph of five tasks, A, B, C, D, and E, in which B, C, and D can run in simultaneously when A finishes. Since we only uses one worker thread in the executor, we can deterministically run B first, then D, and C in order of their priority values. The output of the above code is as follows:

Task B: 0
Task D: 1
Task C: 2

Task priorities are just hints to Taskflow's work-stealing scheduler about which task should run before another. Due to the randomness nature of work stealing, there is no guarantee that the scheduler will always follow these hints to run tasks when multiple workers exist.