1.. _Task-Based_Programming:
2
3Task-Based Programming
4======================
5
6
7When striving for performance, programming in terms of threads can be a
8poor way to do multithreaded programming. It is much better to formulate
9your program in terms of *logical tasks*, not threads, for several
10reasons.
11
12
13-  Matching parallelism to available resources
14
15
16-  Faster task startup and shutdown
17
18
19-  More efficient evaluation order
20
21
22-  Improved load balancing
23
24
25-  Higher–level thinking
26
27
28The following paragraphs explain these points in detail.
29
30
31The threads you create with a threading package are *logical* threads,
32which map onto the *physical threads* of the hardware. For computations
33that do not wait on external devices, highest efficiency usually occurs
34when there is exactly one running logical thread per physical thread.
35Otherwise, there can be inefficiencies from the mismatch\ *.
36Undersubscription* occurs when there are not enough running logical
37threads to keep the physical threads working. *Oversubscription* occurs
38when there are more running logical threads than physical threads.
39Oversubscription usually leads to *time sliced* execution of logical
40threads, which incurs overheads as discussed in Appendix A, *Costs of
41Time Slicing*. The scheduler tries to avoid oversubscription, by having
42one logical thread per physical thread, and mapping tasks to logical
43threads, in a way that tolerates interference by other threads from the
44same or other processes.
45
46
47The key advantage of tasks versus logical threads is that tasks are much
48*lighter weight* than logical threads. On Linux systems, starting and
49terminating a task is about 18 times faster than starting and
50terminating a thread. On Windows systems, the ratio is more than 100.
51This is because a thread has its own copy of a lot of resources, such as
52register state and a stack. On Linux, a thread even has its own process
53id. A task in |full_name|, in contrast, is
54typically a small routine, and also, cannot be preempted at the task
55level (though its logical thread can be preempted).
56
57
58Tasks in oneTBB are efficient too because *the scheduler is unfair*. Thread schedulers typically
59distribute time slices in a round-robin fashion. This distribution is
60called "fair", because each logical thread gets its fair share of time.
61Thread schedulers are typically fair because it is the safest strategy
62to undertake without understanding the higher-level organization of a
63program. In task-based programming, the task scheduler does have some
64higher-level information, and so can sacrifice fairness for efficiency.
65Indeed, it often delays starting a task until it can make useful
66progress.
67
68
69The scheduler does *load balancing*. In addition to using the right
70number of threads, it is important to distribute work evenly across
71those threads. As long as you break your program into enough small
72tasks, the scheduler usually does a good job of assigning tasks to
73threads to balance load. With thread-based programming, you are often
74stuck dealing with load-balancing yourself, which can be tricky to get
75right.
76
77
78.. tip::
79   Design your programs to try to create many more tasks than there are
80   threads, and let the task scheduler choose the mapping from tasks to
81   threads.
82
83
84Finally, the main advantage of using tasks instead of threads is that
85they let you think at a higher, task-based, level. With thread-based
86programming, you are forced to think at the low level of physical
87threads to get good efficiency, because you have one logical thread per
88physical thread to avoid undersubscription or oversubscription. You also
89have to deal with the relatively coarse grain of threads. With tasks,
90you can concentrate on the logical dependences between tasks, and leave
91the efficient scheduling to the scheduler.
92
93