<ahref="#DefineAPartitionerForParallelAlgorithms">Define a Partitioner for Parallel Algorithms</a>
</li>
<liclass="level1">
<ahref="#DefineAStaticPartitioner">Define a Static Partitioner</a>
</li>
<liclass="level1">
<ahref="#DefineADynamicPartitioner">Define a Dynamic Partitioner</a>
</li>
<liclass="level1">
<ahref="#DefineAGuidedPartitioner">Define a Guided Partitioner</a>
</li>
<liclass="level1">
<ahref="#DefineAClosureWrapperForAPartitioner">Define a Closure Wrapper for a Partitioner</a>
</li>
</ul>
</div>
<divclass="textblock"><p>A partitioning algorithm allows applications to optimize parallel algorithms using different scheduling methods, such as static partitioning, dynamic partitioning, and guided partitioning.</p>
<p>A partitioner defines how to partition and distribute iterations to different workers when running parallel algorithms in Taskflow, such as <aclass="el" href="classtf_1_1FlowBuilder.html#aae3edfa278baa75b08414e083c14c836" title="constructs an STL-styled parallel-for task">tf::Taskflow::for_each</a> and <aclass="el" href="classtf_1_1FlowBuilder.html#a058c250de62b9d1e4305b8ddf03906ee" title="constructs a parallel-transform task">tf::Taskflow::transform</a>. The following example shows how to create parallel-iteration tasks with different execution policies:</p>
<divclass="ttc" id="aclasstf_1_1DynamicPartitioner_html"><divclass="ttname"><ahref="classtf_1_1DynamicPartitioner.html">tf::DynamicPartitioner</a></div><divclass="ttdoc">class to create a dynamic partitioner for scheduling parallel algorithms</div><divclass="ttdef"><b>Definition</b> partitioner.hpp:567</div></div>
<divclass="ttc" id="aclasstf_1_1GuidedPartitioner_html"><divclass="ttname"><ahref="classtf_1_1GuidedPartitioner.html">tf::GuidedPartitioner</a></div><divclass="ttdoc">class to create a guided partitioner for scheduling parallel algorithms</div><divclass="ttdef"><b>Definition</b> partitioner.hpp:402</div></div>
<divclass="ttc" id="aclasstf_1_1RandomPartitioner_html"><divclass="ttname"><ahref="classtf_1_1RandomPartitioner.html">tf::RandomPartitioner</a></div><divclass="ttdoc">class to construct a random partitioner for scheduling parallel algorithms</div><divclass="ttdef"><b>Definition</b> partitioner.hpp:691</div></div>
<divclass="ttc" id="aclasstf_1_1StaticPartitioner_html"><divclass="ttname"><ahref="classtf_1_1StaticPartitioner.html">tf::StaticPartitioner</a></div><divclass="ttdoc">class to construct a static partitioner for scheduling parallel algorithms</div><divclass="ttdef"><b>Definition</b> partitioner.hpp:262</div></div>
</div><!-- fragment --><p>Each partitioner has a specific algorithm to partition iterations into a set of <em>chunks</em> and distribute chunks to workers. A chunk is the basic unit of work that will be run by a worker during the execution of parallel iterations. The following figure illustrates the scheduling diagram for three major partitioners, <aclass="el" href="classtf_1_1StaticPartitioner.html" title="class to construct a static partitioner for scheduling parallel algorithms">tf::StaticPartitioner</a>, <aclass="el" href="classtf_1_1DynamicPartitioner.html" title="class to create a dynamic partitioner for scheduling parallel algorithms">tf::DynamicPartitioner</a>, and <aclass="el" href="classtf_1_1GuidedPartitioner.html" title="class to create a guided partitioner for scheduling parallel algorithms">tf::GuidedPartitioner</a>:</p>
<divclass="dotgraph">
<iframescrolling="no" frameborder="0" src="dot_parallel_for_partitioning_algorithms.svg" width="708" height="472"><p><b>This browser is not able to show SVG: try Firefox, Chrome, Safari, or Opera instead.</b></p></iframe></div>
<p>Depending on applications, partitioning algorithms can impact the performance a lot. For example, if a parallel-iteration workload contains a regular work unit per iteration, <aclass="el" href="classtf_1_1StaticPartitioner.html" title="class to construct a static partitioner for scheduling parallel algorithms">tf::StaticPartitioner</a> may deliver the best performance. On the other hand, if the work unit per iteration is irregular and unbalanced, <aclass="el" href="classtf_1_1GuidedPartitioner.html" title="class to create a guided partitioner for scheduling parallel algorithms">tf::GuidedPartitioner</a> or <aclass="el" href="classtf_1_1DynamicPartitioner.html" title="class to create a dynamic partitioner for scheduling parallel algorithms">tf::DynamicPartitioner</a> can outperform <aclass="el" href="classtf_1_1StaticPartitioner.html" title="class to construct a static partitioner for scheduling parallel algorithms">tf::StaticPartitioner</a>.</p>
<dlclass="section note"><dt>Note</dt><dd>By default, all parallel algorithms in Taskflow use <aclass="el" href="namespacetf.html#ace2c5adcd5039483eebb6dbdbb6f33e3" title="default partitioner set to tf::GuidedPartitioner">tf::DefaultPartitioner</a>, which is based on guided scheduling via <aclass="el" href="classtf_1_1GuidedPartitioner.html" title="class to create a guided partitioner for scheduling parallel algorithms">tf::GuidedPartitioner</a>.</dd></dl>
<p>Static partitioner splits iterations into <code>iter_size/chunk_size</code> chunks and distribute chunks to workers in order. If no chunk size is given (<code>chunk_size</code> is 0), Taskflow will partition iterations into chunks that are approximately equal in size. The following code creates a static partitioner with chunk size equal to 100:</p>
</div><!-- fragment --><h1><aclass="anchor" id="DefineADynamicPartitioner"></a>
Define a Dynamic Partitioner</h1>
<p>Dynamic partitioner splits iterations into <code>iter_size/chunk_size</code> chunks and distribute chunks to workers without any specific order. If no chunk size is given (<code>chunk_size</code> is 0), Taskflow will use 1 for the minimum size of a partition. The following code creates a dynamic partitioner with chunk size equal to 2:</p>
</div><!-- fragment --><h1><aclass="anchor" id="DefineAGuidedPartitioner"></a>
Define a Guided Partitioner</h1>
<p>Guided partitioner dynamically decides the chunk size. The size of a chunk is proportional to the number of unassigned iterations divided by the number of the threads, and the size will gradually decrease to the specified chunk size (default 1). The last chunk may be smaller than the specified chunk size. If no chunk size is given (<code>chunk_size</code> is 0), Taskflow will use 1 for the minimum size of a partition. The following code creates a guided partitioner with chunk size equal to 10:</p>
</div><!-- fragment --><p>In most situations, guided partitioner can achieve decent performance due to adaptive parallelism, especially for those with irregular and unbalanced workload per iteration. As a result, guided partitioner is used as the default partitioner for our parallel algorithms.</p>
<p>In addition to partition size, applications can specify a <em>closure wrapper</em> for a partitioner. A closure wrapper allows the application to wrap a partitioned task, i.e., closure, with a custom function object that performs additional tasks. For example:</p>
<divclass="ttc" id="aclasstf_1_1FlowBuilder_html_a3b132bd902331a11b04b4ad66cf8bf77"><divclass="ttname"><ahref="classtf_1_1FlowBuilder.html#a3b132bd902331a11b04b4ad66cf8bf77">tf::FlowBuilder::for_each_index</a></div><divclass="ttdeci">Task for_each_index(B first, E last, S step, C callable, P part=P())</div><divclass="ttdoc">constructs an index-based parallel-for task</div></div>
<divclass="ttc" id="aclasstf_1_1Taskflow_html"><divclass="ttname"><ahref="classtf_1_1Taskflow.html">tf::Taskflow</a></div><divclass="ttdoc">class to create a taskflow object</div><divclass="ttdef"><b>Definition</b> taskflow.hpp:64</div></div>
</div><!-- fragment --><p>Each partitioner uses a default closure wrapper (<aclass="el" href="classtf_1_1DefaultClosureWrapper.html" title="class to create a default closure wrapper">tf::DefaultClosureWrapper</a>) that does nothing but simply invokes the given closure to perform the ordinary partitioned task.</p>