<li><ahref="#LaunchAsynchronousTasksFromAnExecutor">Launch Asynchronous Tasks from an Executor</a></li>
<li><ahref="#LaunchAsynchronousTasksFromAnSubflow">Launch Asynchronous Tasks from a Subflow</a></li>
</ul>
</div>
<p>This chapters discusses how to launch tasks asynchronously so that you can incorporate independent, dynamic parallelism in your taskflows.</p><sectionid="LaunchAsynchronousTasksFromAnExecutor"><h2><ahref="#LaunchAsynchronousTasksFromAnExecutor">Launch Asynchronous Tasks from an Executor</a></h2><p>Taskflow executor provides a STL-styled method, <ahref="classtf_1_1Executor.html#a1e6866c8f1b6a2e932f06d0b4eb032c0" class="m-doc">tf::<wbr/>Executor::<wbr/>async</a>, for you to run a callable object asynchronously. The method returns a <ahref="classtf_1_1Future.html" class="m-doc">tf::<wbr/>Future</a> object derived from <ahref="https://en.cppreference.com/w/cpp/thread/future">std::<wbr/>future</a> that will eventually hold the result of that function call. The result may be optional due to <ahref="classtf_1_1Future.html#a3bf5f104864ab2590b6409712d3a469b" class="m-doc">tf::<wbr/>Future::<wbr/>cancel</a> (see <ahref="RequestCancellation.html" class="m-doc">Request Cancellation</a> for details).</p><preclass="m-code"><spanclass="n">tf</span><spanclass="o">::</span><spanclass="n">Future</span><spanclass="o"><</span><spanclass="n">std</span><spanclass="o">::</span><spanclass="n">optional</span><spanclass="o"><</span><spanclass="kt">int</span><spanclass="o">>></span><spanclass="n">future</span><spanclass="o">=</span><spanclass="n">executor</span><spanclass="p">.</span><spanclass="n">async</span><spanclass="p">([](){</span><spanclass="k">return</span><spanclass="mi">1</span><spanclass="p">;</span><spanclass="p">});</span>
<spanclass="n">future_of_void_return</span><spanclass="p">.</span><spanclass="n">get</span><spanclass="p">();</span></pre><asideclass="m-note m-info"><h4>Note</h4><p>The future object returned from <ahref="classtf_1_1Executor.html#a1e6866c8f1b6a2e932f06d0b4eb032c0" class="m-doc">tf::<wbr/>Executor::<wbr/>async</a> does not block on destruction.</p></aside><p>If you do not need the return value or the future, you can use <ahref="classtf_1_1Executor.html#abf71e7ec0026ddfce79c912264369bc9" class="m-doc">tf::<wbr/>Executor::<wbr/>silent_async</a> which has less overhead of creating an asynchronous task compared to <ahref="classtf_1_1Executor.html#a1e6866c8f1b6a2e932f06d0b4eb032c0" class="m-doc">tf::<wbr/>Executor::<wbr/>async</a>.</p><preclass="m-code"><spanclass="n">executor</span><spanclass="p">.</span><spanclass="n">silent_async</span><spanclass="p">([](){</span>
<spanclass="c1">// just do some stuff in the background ...</span>
<spanclass="p">});</span></pre><p>Launching asynchronous tasks from an executor is <em>thread-safe</em> and can be called from multiple threads or from the execution of a task. Our scheduler autonomously detects whether an asynchronous task is submitted from an external thread or a worker thread and schedules its execution in an efficient work-stealing loop.</p><preclass="m-code"><spanclass="n">tf</span><spanclass="o">::</span><spanclass="n">Task</span><spanclass="n">my_task</span><spanclass="o">=</span><spanclass="n">taskflow</span><spanclass="p">.</span><spanclass="n">emplace</span><spanclass="p">([</span><spanclass="o">&</span><spanclass="p">](){</span>
<spanclass="c1">// do some stuff</span>
<spanclass="c1">// ...</span>
<spanclass="c1">// launch an asynchronous task from my_task</span>
<spanclass="n">executor</span><spanclass="p">.</span><spanclass="n">wait_for_all</span><spanclass="p">();</span><spanclass="c1">// wait for all tasks to finish</span></pre><asideclass="m-note m-info"><h4>Note</h4><p>Asynchronous tasks created from an executor does not belong to any taskflows.</p></aside></section><sectionid="LaunchAsynchronousTasksFromAnSubflow"><h2><ahref="#LaunchAsynchronousTasksFromAnSubflow">Launch Asynchronous Tasks from a Subflow</a></h2><p>You can launch asynchronous tasks from a subflow (<ahref="classtf_1_1Subflow.html" class="m-doc">tf::<wbr/>Subflow</a>) using <ahref="classtf_1_1Subflow.html#a70681068507b224a96df69cc1f3168f1" class="m-doc">tf::<wbr/>Subflow::<wbr/>async</a>. Asynchronous tasks created from a subflow are, and <em>only</em>, used with <em>join</em> (<ahref="classtf_1_1Subflow.html#a59fcac1323e70d920088dd37bd0be245" class="m-doc">tf::<wbr/>Subflow::<wbr/>join</a>) to describe independent tasks that are dynamically spawned during the execution of that subflow. When the subflow joins, all asynchronous tasks are guaranteed to finish. The following code creates 100 asynchronous tasks from a subflow, and these asynchronous tasks will complete by the time the subflow joins.</p><preclass="m-code"><spanclass="n">tf</span><spanclass="o">::</span><spanclass="n">Taskflow</span><spanclass="n">taskflow</span><spanclass="p">;</span>
<spanclass="n">sf</span><spanclass="p">.</span><spanclass="n">join</span><spanclass="p">();</span><spanclass="c1">// all of the 100 asynchronous tasks will finish by this join</span>
<spanclass="n">executor</span><spanclass="p">.</span><spanclass="n">run</span><spanclass="p">(</span><spanclass="n">taskflow</span><spanclass="p">).</span><spanclass="n">wait</span><spanclass="p">();</span></pre><p>If you do not need the return value or the future, you can use <ahref="classtf_1_1Subflow.html#af9671aa8548882b3425e5a1f10f7a868" class="m-doc">tf::<wbr/>Subflow::<wbr/>silent_async</a> which has less overhead of creating an asynchronous task compared to <ahref="classtf_1_1Subflow.html#a70681068507b224a96df69cc1f3168f1" class="m-doc">tf::<wbr/>Subflow::<wbr/>async</a>.</p><preclass="m-code"><spanclass="n">tf</span><spanclass="o">::</span><spanclass="n">Taskflow</span><spanclass="n">taskflow</span><spanclass="p">;</span>
<spanclass="n">sf</span><spanclass="p">.</span><spanclass="n">join</span><spanclass="p">();</span><spanclass="c1">// all of the 100 asynchronous tasks will finish by this join</span>
<spanclass="n">executor</span><spanclass="p">.</span><spanclass="n">run</span><spanclass="p">(</span><spanclass="n">taskflow</span><spanclass="p">).</span><spanclass="n">wait</span><spanclass="p">();</span></pre><p>Creating asynchronous tasks from a subflow allows users to describe, for example, recursive algorithms that define only division without conquering or merging (e.g., parallel quick sort).</p><asideclass="m-note m-warning"><h4>Attention</h4><p>You should only create asynchronous tasks from a joined subflow. Launching asynchronous tasks from a detached subflow results in undefined behavior.</p></aside></section>
</div>
</div>
</div>
</article></main>
<divclass="m-doc-search" id="search">
<ahref="#!" onclick="return hideSearch()"></a>
<divclass="m-container">
<divclass="m-row">
<divclass="m-col-m-8 m-push-m-2">
<divclass="m-doc-search-header m-text m-small">
<div><spanclass="m-label m-default">Tab</span> / <spanclass="m-label m-default">T</span> to search, <spanclass="m-label m-default">Esc</span> to close</div>