<li><ahref="#LaunchAsynchronousTasksFromAnExecutor">Launch Asynchronous Tasks from an Executor</a></li>
<li><ahref="#LaunchAsynchronousTasksFromARuntime">Launch Asynchronous Tasks from a Runtime</a></li>
</ul>
</nav>
<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 an STL-styled method, <ahref="classtf_1_1Executor.html#af960048056f7c6b5bc71f4f526f05df7" class="m-doc">tf::<wbr/>Executor::<wbr/>async</a>, for you to run a callable object asynchronously. The method returns a <ahref="https://en.cppreference.com/w/cpp/thread/future">std::<wbr/>future</a> that will eventually hold the result of that function call.</p><preclass="m-code"><spanclass="n">std</span><spanclass="o">::</span><spanclass="n">future</span><spanclass="o"><</span><spanclass="kt">int</span><spanclass="o">></span><spanclass="w"></span><spanclass="n">future</span><spanclass="w"></span><spanclass="o">=</span><spanclass="w"></span><spanclass="n">executor</span><spanclass="p">.</span><spanclass="n">async</span><spanclass="p">([](){</span><spanclass="w"></span><spanclass="k">return</span><spanclass="w"></span><spanclass="mi">1</span><spanclass="p">;</span><spanclass="w"></span><spanclass="p">});</span>
<spanclass="n">assert</span><spanclass="p">(</span><spanclass="n">future</span><spanclass="p">.</span><spanclass="n">get</span><spanclass="p">()</span><spanclass="w"></span><spanclass="o">==</span><spanclass="w"></span><spanclass="mi">1</span><spanclass="p">);</span></pre><asideclass="m-note m-warning"><h4>Attention</h4><p>Unlike <ahref="http://en.cppreference.com/w/cpp/thread/async.html" class="m-doc-external">std::<wbr/>async</a>, the future object returned from <ahref="classtf_1_1Executor.html#af960048056f7c6b5bc71f4f526f05df7" class="m-doc">tf::<wbr/>Executor::<wbr/>async</a> does not block on destruction until completing the function.</p></aside><p>If you do not need the return value or use a future to synchronize the execution, you are encouraged to use <ahref="classtf_1_1Executor.html#a0461cb2c459c9f9473c72af06af9c701" class="m-doc">tf::<wbr/>Executor::<wbr/>silent_async</a> which returns nothing and thus has less overhead (i.e., no shared state management) compared to <ahref="classtf_1_1Executor.html#af960048056f7c6b5bc71f4f526f05df7" 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="w"></span><spanclass="c1">// do some work without returning any result</span>
<spanclass="p">});</span></pre><p>Launching asynchronous tasks from an executor is <em>thread-safe</em> and can be called by multiple threads both inside (i.e., worker) and outside the executor. Our scheduler autonomously detects whether an asynchronous task is submitted from an external thread or a worker thread and schedules its execution using work stealing.</p><preclass="m-code"><spanclass="n">tf</span><spanclass="o">::</span><spanclass="n">Task</span><spanclass="w"></span><spanclass="n">my_task</span><spanclass="w"></span><spanclass="o">=</span><spanclass="w"></span><spanclass="n">taskflow</span><spanclass="p">.</span><spanclass="n">emplace</span><spanclass="p">([</span><spanclass="o">&</span><spanclass="p">](){</span>
<spanclass="w"></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="w"></span><spanclass="c1">// wait for all tasks to finish</span></pre><asideclass="m-note m-warning"><h4>Attention</h4><p>Asynchronous tasks created from an executor does not belong to any taskflows. The lifetime of an asynchronous task is managed automatically by the executor that creates the task.</p></aside><p>You can name an asynchronous task using the overloads, tf::Executor::async(const std::string& name, F&& f) and tf::Executor::silent_async(const std::string& name, F&& f), that take a string in the first argument. Assigned names will appear in the observers of the executor.</p><preclass="m-code"><spanclass="n">std</span><spanclass="o">::</span><spanclass="n">future</span><spanclass="o"><</span><spanclass="kt">void</span><spanclass="o">></span><spanclass="w"></span><spanclass="n">fu</span><spanclass="w"></span><spanclass="o">=</span><spanclass="w"></span><spanclass="n">executor</span><spanclass="p">.</span><spanclass="n">async</span><spanclass="p">(</span><spanclass="s">"async task"</span><spanclass="p">,</span><spanclass="w"></span><spanclass="p">[](){});</span>
<spanclass="n">executor</span><spanclass="p">.</span><spanclass="n">silent_async</span><spanclass="p">(</span><spanclass="s">"silent async task"</span><spanclass="p">,</span><spanclass="w"></span><spanclass="p">[](){});</span></pre></section><sectionid="LaunchAsynchronousTasksFromARuntime"><h2><ahref="#LaunchAsynchronousTasksFromARuntime">Launch Asynchronous Tasks from a Runtime</a></h2><p>You can launch asynchronous tasks from <ahref="classtf_1_1Runtime.html" class="m-doc">tf::<wbr/>Runtime</a> using <ahref="classtf_1_1Runtime.html#a5688b13034f179c4a8b2b0ebbb215051" class="m-doc">tf::<wbr/>Runtime::<wbr/>async</a> or <ahref="classtf_1_1Runtime.html#a0ce29efa2106c8c5a1432e4a55ab2e05" class="m-doc">tf::<wbr/>Runtime::<wbr/>silent_async</a>. The following code creates 100 asynchronous tasks from a runtime and joins their executions explicitly using <ahref="classtf_1_1Runtime.html#afcc18484a95fd2a834940d878eaf4dfc" class="m-doc">tf::<wbr/>Runtime::<wbr/>corun_all</a>.</p><preclass="m-code"><spanclass="n">tf</span><spanclass="o">::</span><spanclass="n">Taskflow</span><spanclass="w"></span><spanclass="n">taskflow</span><spanclass="p">;</span>
<spanclass="w"></span><spanclass="n">rt</span><spanclass="p">.</span><spanclass="n">corun_all</span><spanclass="p">();</span><spanclass="w"></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>Unlike <ahref="classtf_1_1Subflow.html#a59fcac1323e70d920088dd37bd0be245" class="m-doc">tf::<wbr/>Subflow::<wbr/>join</a>, you can call <ahref="classtf_1_1Runtime.html#afcc18484a95fd2a834940d878eaf4dfc" class="m-doc">tf::<wbr/>Runtime::<wbr/>corun_all</a> multiple times to synchronize the execution of asynchronous tasks between different runs. For example, the following code spawn 100 asynchronous tasks twice and join each execution to assure the spawned 100 asynchronous tasks have properly completed.</p><preclass="m-code"><spanclass="n">tf</span><spanclass="o">::</span><spanclass="n">Taskflow</span><spanclass="w"></span><spanclass="n">taskflow</span><spanclass="p">;</span>
<spanclass="w"></span><spanclass="n">rt</span><spanclass="p">.</span><spanclass="n">corun_all</span><spanclass="p">();</span><spanclass="w"></span><spanclass="c1">// all of the 100 asynchronous tasks will finish by this join</span>
<spanclass="w"></span><spanclass="n">rt</span><spanclass="p">.</span><spanclass="n">corun_all</span><spanclass="p">();</span><spanclass="w"></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>By default, <ahref="classtf_1_1Runtime.html" class="m-doc">tf::<wbr/>Runtime</a> does not join like <ahref="classtf_1_1Subflow.html" class="m-doc">tf::<wbr/>Subflow</a>. All pending asynchronous tasks spawned by <ahref="classtf_1_1Runtime.html" class="m-doc">tf::<wbr/>Runtime</a> are no longer controllable when their parent runtime disappears. It is your responsibility to properly synchronize spawned asynchronous tasks using <ahref="classtf_1_1Runtime.html#afcc18484a95fd2a834940d878eaf4dfc" class="m-doc">tf::<wbr/>Runtime::<wbr/>corun_all</a>.</p><asideclass="m-note m-warning"><h4>Attention</h4><p>Creating asynchronous tasks from a runtime allows users to efficiently implement parallel algorithms using recursion, such as parallel sort (<ahref="classtf_1_1FlowBuilder.html#a35e180eb63de6c9f28e43185e837a4fa" class="m-doc">tf::<wbr/>Taskflow::<wbr/>sort</a>), that demands dynamic parallelism at runtime.</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>