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