forked from taskflow/taskflow
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAsyncTasking.html
More file actions
161 lines (154 loc) · 22.6 KB
/
AsyncTasking.html
File metadata and controls
161 lines (154 loc) · 22.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Cookbook » Asynchronous Tasking | Taskflow QuickStart</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,400i,600,600i%7CSource+Code+Pro:400,400i,600" />
<link rel="stylesheet" href="m-dark+documentation.compiled.css" />
<link rel="icon" href="favicon.ico" type="image/vnd.microsoft.icon" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#22272e" />
</head>
<body>
<header><nav id="navigation">
<div class="m-container">
<div class="m-row">
<span id="m-navbar-brand" class="m-col-t-8 m-col-m-none m-left-m">
<a href="https://taskflow.github.io"><img src="taskflow_logo.png" alt="" />Taskflow</a> <span class="m-breadcrumb">|</span> <a href="index.html" class="m-thin">QuickStart</a>
</span>
<div class="m-col-t-4 m-hide-m m-text-right m-nopadr">
<a href="#search" class="m-doc-search-icon" title="Search" onclick="return showSearch()"><svg style="height: 0.9rem;" viewBox="0 0 16 16">
<path id="m-doc-search-icon-path" d="m6 0c-3.31 0-6 2.69-6 6 0 3.31 2.69 6 6 6 1.49 0 2.85-0.541 3.89-1.44-0.0164 0.338 0.147 0.759 0.5 1.15l3.22 3.79c0.552 0.614 1.45 0.665 2 0.115 0.55-0.55 0.499-1.45-0.115-2l-3.79-3.22c-0.392-0.353-0.812-0.515-1.15-0.5 0.895-1.05 1.44-2.41 1.44-3.89 0-3.31-2.69-6-6-6zm0 1.56a4.44 4.44 0 0 1 4.44 4.44 4.44 4.44 0 0 1-4.44 4.44 4.44 4.44 0 0 1-4.44-4.44 4.44 4.44 0 0 1 4.44-4.44z"/>
</svg></a>
<a id="m-navbar-show" href="#navigation" title="Show navigation"></a>
<a id="m-navbar-hide" href="#" title="Hide navigation"></a>
</div>
<div id="m-navbar-collapse" class="m-col-t-12 m-show-m m-col-m-none m-right-m">
<div class="m-row">
<ol class="m-col-t-6 m-col-m-none">
<li><a href="pages.html">Handbook</a></li>
<li><a href="namespaces.html">Namespaces</a></li>
</ol>
<ol class="m-col-t-6 m-col-m-none" start="3">
<li><a href="annotated.html">Classes</a></li>
<li><a href="files.html">Files</a></li>
<li class="m-show-m"><a href="#search" class="m-doc-search-icon" title="Search" onclick="return showSearch()"><svg style="height: 0.9rem;" viewBox="0 0 16 16">
<use href="#m-doc-search-icon-path" />
</svg></a></li>
</ol>
</div>
</div>
</div>
</div>
</nav></header>
<main><article>
<div class="m-container m-container-inflatable">
<div class="m-row">
<div class="m-col-l-10 m-push-l-1">
<h1>
<span class="m-breadcrumb"><a href="Cookbook.html">Cookbook</a> »</span>
Asynchronous Tasking
</h1>
<nav class="m-block m-default">
<h3>Contents</h3>
<ul>
<li><a href="#LaunchAsynchronousTasksFromAnExecutor">Launch Asynchronous Tasks from an Executor</a></li>
<li><a href="#LaunchAsynchronousTasksFromAnSubflow">Launch Asynchronous Tasks from a Subflow</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><section id="LaunchAsynchronousTasksFromAnExecutor"><h2><a href="#LaunchAsynchronousTasksFromAnExecutor">Launch Asynchronous Tasks from an Executor</a></h2><p>Taskflow executor provides a STL-styled method, <a href="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 <a href="classtf_1_1Future.html" class="m-doc">tf::<wbr />Future</a> object derived from <a href="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 <a href="classtf_1_1Future.html#a3bf5f104864ab2590b6409712d3a469b" class="m-doc">tf::<wbr />Future::<wbr />cancel</a> (see <a href="RequestCancellation.html" class="m-doc">Request Cancellation</a> for details).</p><pre class="m-code"><span class="n">tf</span><span class="o">::</span><span class="n">Future</span><span class="o"><</span><span class="n">std</span><span class="o">::</span><span class="n">optional</span><span class="o"><</span><span class="kt">int</span><span class="o">>></span><span class="w"> </span><span class="n">future</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">executor</span><span class="p">.</span><span class="n">async</span><span class="p">([](){</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"> </span><span class="p">});</span><span class="w"></span>
<span class="n">executor</span><span class="p">.</span><span class="n">wait_for_all</span><span class="p">();</span><span class="w"></span>
<span class="n">assert</span><span class="p">(</span><span class="n">future</span><span class="p">.</span><span class="n">get</span><span class="p">()</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">1</span><span class="p">);</span><span class="w"></span>
<span class="n">tf</span><span class="o">::</span><span class="n">Future</span><span class="o"><</span><span class="kt">void</span><span class="o">></span><span class="w"> </span><span class="n">future_of_void_return</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">executor</span><span class="p">.</span><span class="n">async</span><span class="p">([](){});</span><span class="w"></span>
<span class="n">future_of_void_return</span><span class="p">.</span><span class="n">get</span><span class="p">();</span><span class="w"></span></pre><aside class="m-note m-info"><h4>Note</h4><p>The future object returned from <a href="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 <a href="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 <a href="classtf_1_1Executor.html#a1e6866c8f1b6a2e932f06d0b4eb032c0" class="m-doc">tf::<wbr />Executor::<wbr />async</a>.</p><pre class="m-code"><span class="n">executor</span><span class="p">.</span><span class="n">silent_async</span><span class="p">([](){</span><span class="w"></span>
<span class="w"> </span><span class="c1">// just do some stuff in the background ...</span>
<span class="p">});</span><span class="w"></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><pre class="m-code"><span class="n">tf</span><span class="o">::</span><span class="n">Task</span><span class="w"> </span><span class="n">my_task</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">taskflow</span><span class="p">.</span><span class="n">emplace</span><span class="p">([</span><span class="o">&</span><span class="p">](){</span><span class="w"></span>
<span class="w"> </span><span class="c1">// do some stuff</span>
<span class="w"> </span><span class="c1">// ...</span>
<span class="w"> </span><span class="c1">// launch an asynchronous task from my_task</span>
<span class="w"> </span><span class="n">executor</span><span class="p">.</span><span class="n">async</span><span class="p">([</span><span class="o">&</span><span class="p">](){</span><span class="w"></span>
<span class="w"> </span><span class="c1">// do another asynchronous work</span>
<span class="w"> </span><span class="c1">// ...</span>
<span class="w"> </span><span class="c1">// launch another asynchronous task</span>
<span class="w"> </span><span class="n">executor</span><span class="p">.</span><span class="n">async</span><span class="p">([</span><span class="o">&</span><span class="p">](){});</span><span class="w"></span>
<span class="w"> </span><span class="p">})</span><span class="w"></span>
<span class="p">});</span><span class="w"></span>
<span class="n">executor</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">taskflow</span><span class="p">);</span><span class="w"></span>
<span class="n">executor</span><span class="p">.</span><span class="n">wait_for_all</span><span class="p">();</span><span class="w"> </span><span class="c1">// wait for all tasks to finish</span></pre><aside class="m-note m-info"><h4>Note</h4><p>Asynchronous tasks created from an executor does not belong to any taskflows.</p></aside><p>You can name an asynchronous task to facilitate profiling by using the methods <a href="classtf_1_1Executor.html#a51acee1670e9f246c7ccd7f6a63f1524" class="m-doc">tf::<wbr />Executor::<wbr />named_async</a> and <a href="classtf_1_1Executor.html#a1febfaa7a99cac8466263c58fd2a7c06" class="m-doc">tf::<wbr />Executor::<wbr />named_silent_async</a>.</p><pre class="m-code"><span class="n">tf</span><span class="o">::</span><span class="n">Future</span><span class="o"><</span><span class="kt">void</span><span class="o">></span><span class="w"> </span><span class="n">future</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">executor</span><span class="p">.</span><span class="n">named_async</span><span class="p">(</span><span class="s">"name of the task"</span><span class="p">,</span><span class="w"> </span><span class="p">[](){});</span><span class="w"></span>
<span class="n">executor</span><span class="p">.</span><span class="n">silent_named_async</span><span class="p">(</span><span class="s">"another name of the task"</span><span class="p">,</span><span class="w"> </span><span class="p">[](){});</span><span class="w"></span></pre></section><section id="LaunchAsynchronousTasksFromAnSubflow"><h2><a href="#LaunchAsynchronousTasksFromAnSubflow">Launch Asynchronous Tasks from a Subflow</a></h2><p>You can launch asynchronous tasks from a subflow (<a href="classtf_1_1Subflow.html" class="m-doc">tf::<wbr />Subflow</a>) using <a href="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> (<a href="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><pre class="m-code"><span class="n">tf</span><span class="o">::</span><span class="n">Taskflow</span><span class="w"> </span><span class="n">taskflow</span><span class="p">;</span><span class="w"></span>
<span class="n">tf</span><span class="o">::</span><span class="n">Executor</span><span class="w"> </span><span class="n">executor</span><span class="p">;</span><span class="w"></span>
<span class="n">std</span><span class="o">::</span><span class="n">atomic</span><span class="o"><</span><span class="kt">int</span><span class="o">></span><span class="w"> </span><span class="n">counter</span><span class="p">{</span><span class="mi">0</span><span class="p">};</span><span class="w"></span>
<span class="n">taskflow</span><span class="p">.</span><span class="n">emplace</span><span class="p">([</span><span class="o">&</span><span class="p">]</span><span class="w"> </span><span class="p">(</span><span class="n">tf</span><span class="o">::</span><span class="n">Subflow</span><span class="o">&</span><span class="w"> </span><span class="n">sf</span><span class="p">){</span><span class="w"></span>
<span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o"><</span><span class="n">tf</span><span class="o">::</span><span class="n">Future</span><span class="o"><</span><span class="kt">void</span><span class="o">>></span><span class="w"> </span><span class="n">futures</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">for</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o"><</span><span class="mi">100</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">futures</span><span class="p">.</span><span class="n">emplace_back</span><span class="p">(</span><span class="n">sf</span><span class="p">.</span><span class="n">async</span><span class="p">([</span><span class="o">&</span><span class="p">](){</span><span class="w"> </span><span class="o">++</span><span class="n">counter</span><span class="p">;</span><span class="w"> </span><span class="p">}));</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="n">sf</span><span class="p">.</span><span class="n">join</span><span class="p">();</span><span class="w"> </span><span class="c1">// all of the 100 asynchronous tasks will finish by this join</span>
<span class="w"> </span><span class="n">assert</span><span class="p">(</span><span class="n">counter</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">100</span><span class="p">);</span><span class="w"></span>
<span class="p">});</span><span class="w"></span>
<span class="n">executor</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">taskflow</span><span class="p">).</span><span class="n">wait</span><span class="p">();</span><span class="w"></span></pre><p>If you do not need the return value or the future, you can use <a href="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 <a href="classtf_1_1Subflow.html#a70681068507b224a96df69cc1f3168f1" class="m-doc">tf::<wbr />Subflow::<wbr />async</a>.</p><pre class="m-code"><span class="n">tf</span><span class="o">::</span><span class="n">Taskflow</span><span class="w"> </span><span class="n">taskflow</span><span class="p">;</span><span class="w"></span>
<span class="n">tf</span><span class="o">::</span><span class="n">Executor</span><span class="w"> </span><span class="n">executor</span><span class="p">;</span><span class="w"></span>
<span class="n">std</span><span class="o">::</span><span class="n">atomic</span><span class="o"><</span><span class="kt">int</span><span class="o">></span><span class="w"> </span><span class="n">counter</span><span class="p">{</span><span class="mi">0</span><span class="p">};</span><span class="w"></span>
<span class="n">taskflow</span><span class="p">.</span><span class="n">emplace</span><span class="p">([</span><span class="o">&</span><span class="p">]</span><span class="w"> </span><span class="p">(</span><span class="n">tf</span><span class="o">::</span><span class="n">Subflow</span><span class="o">&</span><span class="w"> </span><span class="n">sf</span><span class="p">){</span><span class="w"></span>
<span class="w"> </span><span class="k">for</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o"><</span><span class="mi">100</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="n">sf</span><span class="p">.</span><span class="n">silent_async</span><span class="p">([</span><span class="o">&</span><span class="p">](){</span><span class="w"> </span><span class="o">++</span><span class="n">counter</span><span class="p">;</span><span class="w"> </span><span class="p">});</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="w"> </span><span class="n">sf</span><span class="p">.</span><span class="n">join</span><span class="p">();</span><span class="w"> </span><span class="c1">// all of the 100 asynchronous tasks will finish by this join</span>
<span class="w"> </span><span class="n">assert</span><span class="p">(</span><span class="n">counter</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">100</span><span class="p">);</span><span class="w"></span>
<span class="p">});</span><span class="w"></span>
<span class="n">executor</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">taskflow</span><span class="p">).</span><span class="n">wait</span><span class="p">();</span><span class="w"></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><aside class="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><p>Similar to <a href="classtf_1_1Executor.html#a51acee1670e9f246c7ccd7f6a63f1524" class="m-doc">tf::<wbr />Executor::<wbr />named_async</a> and <a href="classtf_1_1Executor.html#a1febfaa7a99cac8466263c58fd2a7c06" class="m-doc">tf::<wbr />Executor::<wbr />named_silent_async</a>, you can name an asynchronous task in <a href="classtf_1_1Subflow.html" class="m-doc">tf::<wbr />Subflow</a> to facilitate profiling by using the methods <a href="classtf_1_1Subflow.html#ae528c2de98ec89afc50b8815c0306b5e" class="m-doc">tf::<wbr />Subflow::<wbr />named_async</a> and <a href="classtf_1_1Subflow.html#a3290b8f729c4511f2023199e4c067951" class="m-doc">tf::<wbr />Subflow::<wbr />named_silent_async</a>.</p><pre class="m-code"><span class="n">taskflow</span><span class="p">.</span><span class="n">emplace</span><span class="p">([](</span><span class="n">tf</span><span class="o">::</span><span class="n">Subflow</span><span class="o">&</span><span class="w"> </span><span class="n">sf</span><span class="p">){</span><span class="w"></span>
<span class="w"> </span><span class="n">tf</span><span class="o">::</span><span class="n">Future</span><span class="o"><</span><span class="kt">void</span><span class="o">></span><span class="w"> </span><span class="n">future</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">sf</span><span class="p">.</span><span class="n">named_async</span><span class="p">(</span><span class="s">"name of the task"</span><span class="p">,</span><span class="w"> </span><span class="p">[](){});</span><span class="w"></span>
<span class="w"> </span><span class="n">sf</span><span class="p">.</span><span class="n">silent_named_async</span><span class="p">(</span><span class="s">"another name of the task"</span><span class="p">,</span><span class="w"> </span><span class="p">[](){});</span><span class="w"></span>
<span class="w"> </span><span class="n">sf</span><span class="p">.</span><span class="n">join</span><span class="p">();</span><span class="w"></span>
<span class="p">});</span><span class="w"></span></pre></section>
</div>
</div>
</div>
</article></main>
<div class="m-doc-search" id="search">
<a href="#!" onclick="return hideSearch()"></a>
<div class="m-container">
<div class="m-row">
<div class="m-col-m-8 m-push-m-2">
<div class="m-doc-search-header m-text m-small">
<div><span class="m-label m-default">Tab</span> / <span class="m-label m-default">T</span> to search, <span class="m-label m-default">Esc</span> to close</div>
<div id="search-symbolcount">…</div>
</div>
<div class="m-doc-search-content">
<form>
<input type="search" name="q" id="search-input" placeholder="Loading …" disabled="disabled" autofocus="autofocus" autocomplete="off" spellcheck="false" />
</form>
<noscript class="m-text m-danger m-text-center">Unlike everything else in the docs, the search functionality <em>requires</em> JavaScript.</noscript>
<div id="search-help" class="m-text m-dim m-text-center">
<p class="m-noindent">Search for symbols, directories, files, pages or
modules. You can omit any prefix from the symbol or file path; adding a
<code>:</code> or <code>/</code> suffix lists all members of given symbol or
directory.</p>
<p class="m-noindent">Use <span class="m-label m-dim">↓</span>
/ <span class="m-label m-dim">↑</span> to navigate through the list,
<span class="m-label m-dim">Enter</span> to go.
<span class="m-label m-dim">Tab</span> autocompletes common prefix, you can
copy a link to the result using <span class="m-label m-dim">⌘</span>
<span class="m-label m-dim">L</span> while <span class="m-label m-dim">⌘</span>
<span class="m-label m-dim">M</span> produces a Markdown link.</p>
</div>
<div id="search-notfound" class="m-text m-warning m-text-center">Sorry, nothing was found.</div>
<ul id="search-results"></ul>
</div>
</div>
</div>
</div>
</div>
<script src="search-v2.js"></script>
<script src="searchdata-v2.js" async="async"></script>
<footer><nav>
<div class="m-container">
<div class="m-row">
<div class="m-col-l-10 m-push-l-1">
<p>Taskflow handbook is part of the <a href="https://taskflow.github.io">Taskflow project</a>, copyright © <a href="https://tsung-wei-huang.github.io/">Dr. Tsung-Wei Huang</a>, 2018–2022.<br />Generated by <a href="https://doxygen.org/">Doxygen</a> 1.8.14 and <a href="https://mcss.mosra.cz/">m.css</a>.</p>
</div>
</div>
</div>
</nav></footer>
</body>
</html>