<!-- iframe showing the search results (closed by default) -->
<divid="MSearchResultsWindow">
<iframesrc="javascript:void(0)" frameborder="0"
name="MSearchResults" id="MSearchResults">
</iframe>
</div>
<divclass="header">
<divclass="headertitle">
<divclass="title">C3: Create a Parallel For-loop Graph </div></div>
</div><!--header-->
<divclass="contents">
<divclass="textblock"><p>Running a for-loop in parallel is the most fundamental building block in parallel programming. In this chapter, we are going to demonstrate how to use Cpp-Taskflow to create a task dependency graph of parallel for-loop.</p>
<h1><aclass="anchor" id="RangeBasedForLoop"></a>
Range-based For-loop</h1>
<p>Cpp-Taskflow has a STL-style method <aclass="el" href="classtf_1_1FlowBuilder.html#a644d7ff0f19ca155a2e7d56b1cdb3a0b" title="constructs a task dependency graph of range-based parallel_for ">tf::Taskflow::parallel_for(I beg, I end, C&& callable, size_t partitions)</a> that partitions a range of items and applies a callable to each item in the partition in parallel. The method constructs a task dependency graph representing this workload and returns a task pair as two synchronization points to this task graph.</p>
<divclass="fragment"><divclass="line"> 1: <aclass="code" href="classtf_1_1Taskflow.html">tf::Taskflow</a> taskflow;</div><divclass="line"> 2:</div><divclass="line"> 3: <aclass="codeRef" doxygen="/home/tsung-wei/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/container/vector.html">std::vector<int></a> items {1, 2, 3, 4, 5, 6, 7, 8};</div><divclass="line"> 4:</div><divclass="line"> 5: <spanclass="keyword">auto</span> [S, T] = taskflow.<aclass="code" href="classtf_1_1FlowBuilder.html#a644d7ff0f19ca155a2e7d56b1cdb3a0b">parallel_for</a>(items.begin(), items.end(), [] (<spanclass="keywordtype">int</span> item) {</div><divclass="line"> 6: <aclass="codeRef" doxygen="/home/tsung-wei/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << <aclass="codeRef" doxygen="/home/tsung-wei/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/thread/get_id.html">std::this_thread::get_id</a>() << <spanclass="stringliteral">" runs "</span> << item << <aclass="codeRef" doxygen="/home/tsung-wei/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/manip/endl.html">std::endl</a>;</div><divclass="line"> 7: });</div><divclass="line"> 8:</div><divclass="line"> 9: S.work([](){ <aclass="codeRef" doxygen="/home/tsung-wei/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << <spanclass="stringliteral">"S\n"</span>; }).name(<spanclass="stringliteral">"S"</span>);</div><divclass="line">10: T.work([](){ <aclass="codeRef" doxygen="/home/tsung-wei/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << <spanclass="stringliteral">"T\n"</span>; }).name(<spanclass="stringliteral">"T"</span>);</div><divclass="line">11:</div><divclass="line">12: taskflow.<aclass="code" href="classtf_1_1Taskflow.html#ac433018262e44b12c4cc9f0c4748d758">dump</a>(<aclass="codeRef" doxygen="/home/tsung-wei/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a>);</div></div><!-- fragment --><p>The above code generates the following task dependency graph. The label 0x56* represents an internal task node to execute the callable object. By default (<code>partitions=0</code>), Cpp-Taskflow evenly partitions and distributes the workload across the maximum hardware concurrency. Suppose our example has four logical cores, each internal node corresponds to a partition taking two items (eight tasks in total).</p>
<li>Line 1 creates a taskflow object of four worker threads </li>
<li>Line 3 creates a vector container of eight items </li>
<li>Line 5-7 creates a parallel execution graph using the method <code>parallel_for</code></li>
<li>Line 9-10 names the synchronization tasks <code>S</code> and <code>T</code></li>
<li>Line 12 dumps the graph to a dot format which can be visualized through <ahref="https://dreampuf.github.io/GraphvizOnline/">GraphViz Online</a></li>
</ul>
<p>Here is one possible output of this program:</p>
<p>By default, Cpp-Taskflow partitions the workload evenly across the workers. In some cases, it is useful to disable this feature and apply user-specified partition. The method <code>parallel_for</code> tasks an unsigned integer <code>partitions</code> as the number of partitions over the items.</p>
<divclass="fragment"><divclass="line"><spanclass="keyword">auto</span> [S, T] = taskflow.<aclass="code" href="classtf_1_1FlowBuilder.html#a644d7ff0f19ca155a2e7d56b1cdb3a0b">parallel_for</a>(items.begin(), items.end(), [] (<spanclass="keywordtype">int</span> item) {</div><divclass="line"><aclass="codeRef" doxygen="/home/tsung-wei/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << <aclass="codeRef" doxygen="/home/tsung-wei/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/thread/get_id.html">std::this_thread::get_id</a>() << <spanclass="stringliteral">" runs "</span> << item << <aclass="codeRef" doxygen="/home/tsung-wei/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/manip/endl.html">std::endl</a>;</div><divclass="line">}, 8);</div></div><!-- fragment --><p>The above example will force each of the eight partitions to run exactly one item. This can be useful when you have unbalanced workload per item and would like to enable more efficient parallelization.</p>
<p>You can explicitly construct a dependency graph that represents a parallel execution of a for-loop using only the basic methods <aclass="el" href="classtf_1_1FlowBuilder.html#a4d52a7fe2814b264846a2085e931652c" title="creates a task from a given callable object ">tf::Taskflow::emplace</a> and <aclass="el" href="classtf_1_1Task.html#a8c78c453295a553c1c016e4062da8588" title="adds precedence links from this to other tasks ">tf::Task::precede</a>.</p>
<p>Cpp-Taskflow provides an overload <aclass="el" href="classtf_1_1FlowBuilder.html#acfce9d2800a097202bdd4047f205dacf" title="constructs a task dependency graph of index-based parallel_for ">tf::Taskflow::parallel_for(I beg, I end, I step, C&& callable, size_t partitions)</a> to parallelize an index-based for-loop. It takes three numbers <code>beg</code>, <code>end</code>, and <code>step</code> of the same type <code>I</code> and applies <code>callable</code> to each index in the range <code>[beg, end)</code> with the step size <code>step</code>.</p>
<divclass="fragment"><divclass="line">1: taskflow.<aclass="code" href="classtf_1_1FlowBuilder.html#a644d7ff0f19ca155a2e7d56b1cdb3a0b">parallel_for</a>(0, 10, 2, [] (<spanclass="keywordtype">int</span> i) {</div><divclass="line">2: <aclass="codeRef" doxygen="/home/tsung-wei/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << <spanclass="stringliteral">"parallel on "</span> << i << <aclass="codeRef" doxygen="/home/tsung-wei/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/manip/endl.html">std::endl</a>;</div><divclass="line">3: });</div><divclass="line">4: <spanclass="comment">// print 0, 2, 4, 6, 8</span></div></div><!-- fragment --><p>It also works on the opposite order with negative step size.</p>
<divclass="fragment"><divclass="line">1: taskflow.<aclass="code" href="classtf_1_1FlowBuilder.html#a644d7ff0f19ca155a2e7d56b1cdb3a0b">parallel_for</a>(10, 0, -2, [] (<spanclass="keywordtype">int</span> i) {</div><divclass="line">2: <aclass="codeRef" doxygen="/home/tsung-wei/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << <spanclass="stringliteral">"parallel on "</span> << i << <aclass="codeRef" doxygen="/home/tsung-wei/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/manip/endl.html">std::endl</a>;</div><divclass="line">3: });</div><divclass="line">4: <spanclass="comment">// print 10, 8, 6, 4, 2</span></div></div><!-- fragment --><p>Similarly, you can explicitly specify the partition size:</p>
<divclass="fragment"><divclass="line">1: taskflow.<aclass="code" href="classtf_1_1FlowBuilder.html#a644d7ff0f19ca155a2e7d56b1cdb3a0b">parallel_for</a>(0, 10, 2, [] (<spanclass="keywordtype">int</span> i) {</div><divclass="line">2: <aclass="codeRef" doxygen="/home/tsung-wei/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/basic_ostream.html">std::cout</a> << <spanclass="stringliteral">"parallel on "</span> << i << <aclass="codeRef" doxygen="/home/tsung-wei/Code/cpp-taskflow/doxygen/cppreference-doxygen-web.tag.xml:http://en.cppreference.com/w/" href="http://en.cppreference.com/w/cpp/io/manip/endl.html">std::endl</a>;</div><divclass="line">3: }, 3);</div><divclass="line">4: <spanclass="comment">// print 0, 2, 4, 6, 8 (three partitions {0, 2}, {4, 6}, {8})</span></div></div><!-- fragment --><p>By default, Cpp-Taskflow performs even partition across the number of available threads if no partition size is given.</p>
<h1><aclass="anchor" id="Chapter3Example1"></a>
Example 1: Parallel Map</h1>
<p>This example demonstrates how to use <aclass="el" href="classtf_1_1FlowBuilder.html#a644d7ff0f19ca155a2e7d56b1cdb3a0b" title="constructs a task dependency graph of range-based parallel_for ">tf::Taskflow::parallel_for</a> to create a parallel map pattern. The map operator modifies each item in the container to one if it is an odd number, or zero if it is an even number.</p>