forked from taskflow/taskflow
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathModuleAlgorithm.xml
More file actions
136 lines (136 loc) · 18.4 KB
/
Copy pathModuleAlgorithm.xml
File metadata and controls
136 lines (136 loc) · 18.4 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
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.12.0" xml:lang="en-US">
<compounddef id="ModuleAlgorithm" kind="page">
<compoundname>ModuleAlgorithm</compoundname>
<title>Module Algorithm</title>
<tableofcontents>
<tocsect>
<name>Include the Header</name>
<reference>ModuleAlgorithm_1ModuleAlgorithmInclude</reference>
</tocsect>
<tocsect>
<name>What is a Module Task</name>
<reference>ModuleAlgorithm_1WhatIsAModuleTask</reference>
</tocsect>
<tocsect>
<name>Create a Module Task over a Custom Graph</name>
<reference>ModuleAlgorithm_1CreateAModuleTaskOverACustomGraph</reference>
</tocsect>
</tableofcontents>
<briefdescription>
</briefdescription>
<detaileddescription>
<para>Taskflow provides template methods that let users create reusable building blocks called <emphasis>modules</emphasis>. Users can connect modules together to build more complex parallel algorithms.</para>
<sect1 id="ModuleAlgorithm_1ModuleAlgorithmInclude">
<title>Include the Header</title><para>You need to include the header file, <computeroutput><ref refid="module_8hpp_source" kindref="compound">taskflow/algorithm/module.hpp</ref></computeroutput>, for creating a module task over a schedulable graph target.</para>
<para><programlisting filename=".cpp"><codeline><highlight class="preprocessor">#include<sp/><taskflow/algorithm/module.hpp></highlight></codeline>
</programlisting></para>
</sect1>
<sect1 id="ModuleAlgorithm_1WhatIsAModuleTask">
<title>What is a Module Task</title><para>Similar to <ref refid="ComposableTasking" kindref="compound">Composable Tasking</ref>, but in a more general setting, the template function <ref refid="namespacetf_1a6c73f8957e0f60c76614243979e3b112" kindref="member">tf::make_module_task</ref> allows you to create a task over a Taskflow graph that can be executed by an executor. This provides a flexible mechanism to encapsulate and reuse complex task logic within your Taskflow applications. The following example demonstrates how to create and launch multiple Taskflow graphs in parallel using asynchronous tasking:</para>
<para><programlisting filename=".cpp"><codeline><highlight class="preprocessor">#include<sp/><<ref refid="taskflow_8hpp" kindref="compound">taskflow/taskflow.hpp</ref>></highlight><highlight class="normal"></highlight></codeline>
<codeline><highlight class="normal"></highlight><highlight class="preprocessor">#include<sp/><taskflow/algorithm/module.hpp></highlight><highlight class="normal"></highlight></codeline>
<codeline><highlight class="normal"></highlight></codeline>
<codeline><highlight class="normal"></highlight><highlight class="keywordtype">int</highlight><highlight class="normal"><sp/>main()<sp/>{</highlight></codeline>
<codeline><highlight class="normal"></highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/><ref refid="classtf_1_1Executor" kindref="compound">tf::Executor</ref><sp/>executor;</highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/></highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/><ref refid="classtf_1_1Taskflow" kindref="compound">tf::Taskflow</ref><sp/>A;</highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/><ref refid="classtf_1_1Taskflow" kindref="compound">tf::Taskflow</ref><sp/>B;</highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/><ref refid="classtf_1_1Taskflow" kindref="compound">tf::Taskflow</ref><sp/>C;</highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/><ref refid="classtf_1_1Taskflow" kindref="compound">tf::Taskflow</ref><sp/>D;</highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/></highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/>A.<ref refid="classtf_1_1FlowBuilder_1a60d7a666cab71ecfa3010b2efb0d6b57" kindref="member">emplace</ref>([](){<sp/>printf(</highlight><highlight class="stringliteral">"Taskflow<sp/>A\n"</highlight><highlight class="normal">);<sp/>});<sp/></highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/>B.<ref refid="classtf_1_1FlowBuilder_1a60d7a666cab71ecfa3010b2efb0d6b57" kindref="member">emplace</ref>([](){<sp/>printf(</highlight><highlight class="stringliteral">"Taskflow<sp/>B\n"</highlight><highlight class="normal">);<sp/>});<sp/></highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/>C.<ref refid="classtf_1_1FlowBuilder_1a60d7a666cab71ecfa3010b2efb0d6b57" kindref="member">emplace</ref>([](){<sp/><ref refid="cpp/io/c/fprintf" kindref="compound" external="/Users/twhuang/Code/taskflow/doxygen/cppreference-doxygen-web.tag.xml">printf</ref>(</highlight><highlight class="stringliteral">"Taskflow<sp/>C\n"</highlight><highlight class="normal">);<sp/>});<sp/></highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/>D.<ref refid="classtf_1_1FlowBuilder_1a60d7a666cab71ecfa3010b2efb0d6b57" kindref="member">emplace</ref>([](){<sp/><ref refid="cpp/io/c/fprintf" kindref="compound" external="/Users/twhuang/Code/taskflow/doxygen/cppreference-doxygen-web.tag.xml">printf</ref>(</highlight><highlight class="stringliteral">"Taskflow<sp/>D\n"</highlight><highlight class="normal">);<sp/>});<sp/></highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/></highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/></highlight><highlight class="comment">//<sp/>launch<sp/>the<sp/>four<sp/>taskflows<sp/>using<sp/>asynchronous<sp/>tasking</highlight><highlight class="normal"></highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/>executor.<ref refid="classtf_1_1Executor_1af960048056f7c6b5bc71f4f526f05df7" kindref="member">async</ref>(<ref refid="namespacetf_1a6c73f8957e0f60c76614243979e3b112" kindref="member">tf::make_module_task</ref>(A));</highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/>executor.<ref refid="classtf_1_1Executor_1af960048056f7c6b5bc71f4f526f05df7" kindref="member">async</ref>(<ref refid="namespacetf_1a6c73f8957e0f60c76614243979e3b112" kindref="member">tf::make_module_task</ref>(B));</highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/>executor.<ref refid="classtf_1_1Executor_1af960048056f7c6b5bc71f4f526f05df7" kindref="member">async</ref>(<ref refid="namespacetf_1a6c73f8957e0f60c76614243979e3b112" kindref="member">tf::make_module_task</ref>(C));</highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/>executor.<ref refid="classtf_1_1Executor_1af960048056f7c6b5bc71f4f526f05df7" kindref="member">async</ref>(<ref refid="namespacetf_1a6c73f8957e0f60c76614243979e3b112" kindref="member">tf::make_module_task</ref>(D));</highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/>executor.<ref refid="classtf_1_1Executor_1ab9aa252f70e9a40020a1e5a89d485b85" kindref="member">wait_for_all</ref>();<sp/><sp/></highlight></codeline>
<codeline><highlight class="normal"></highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/></highlight><highlight class="keywordflow">return</highlight><highlight class="normal"><sp/>0;</highlight></codeline>
<codeline><highlight class="normal">}</highlight></codeline>
</programlisting></para>
<para><dotfile name="module_task_1.dot"></dotfile>
</para>
<para>Since the four taskflows are launched asynchronously without any dependencies between them, we can observe any order of the output message:</para>
<para><programlisting filename=".bash"><codeline><highlight class="normal">#<sp/>one<sp/>possible<sp/>output</highlight></codeline>
<codeline><highlight class="normal">Taskflow<sp/>B</highlight></codeline>
<codeline><highlight class="normal">Taskflow<sp/>C</highlight></codeline>
<codeline><highlight class="normal">Taskflow<sp/>A</highlight></codeline>
<codeline><highlight class="normal">Taskflow<sp/>D</highlight></codeline>
<codeline></codeline>
<codeline><highlight class="normal">#<sp/>another<sp/>possible<sp/>output</highlight></codeline>
<codeline><highlight class="normal">Taskflow<sp/>D</highlight></codeline>
<codeline><highlight class="normal">Taskflow<sp/>A</highlight></codeline>
<codeline><highlight class="normal">Taskflow<sp/>B</highlight></codeline>
<codeline><highlight class="normal">Taskflow<sp/>C</highlight></codeline>
</programlisting></para>
<para>If you need to enforce dependencies among these four taskflows, you can use dependent-async tasks. The example below launches the four taskflows one by one in sequential:</para>
<para><programlisting filename=".cpp"><codeline><highlight class="normal"><ref refid="classtf_1_1Executor" kindref="compound">tf::Executor</ref><sp/>executor;</highlight></codeline>
<codeline><highlight class="normal"></highlight></codeline>
<codeline><highlight class="normal"><ref refid="classtf_1_1Taskflow" kindref="compound">tf::Taskflow</ref><sp/>A;</highlight></codeline>
<codeline><highlight class="normal"><ref refid="classtf_1_1Taskflow" kindref="compound">tf::Taskflow</ref><sp/>B;</highlight></codeline>
<codeline><highlight class="normal"><ref refid="classtf_1_1Taskflow" kindref="compound">tf::Taskflow</ref><sp/>C;</highlight></codeline>
<codeline><highlight class="normal"><ref refid="classtf_1_1Taskflow" kindref="compound">tf::Taskflow</ref><sp/>D;</highlight></codeline>
<codeline><highlight class="normal"></highlight></codeline>
<codeline><highlight class="normal">A.<ref refid="classtf_1_1FlowBuilder_1a60d7a666cab71ecfa3010b2efb0d6b57" kindref="member">emplace</ref>([](){<sp/>printf(</highlight><highlight class="stringliteral">"Taskflow<sp/>A\n"</highlight><highlight class="normal">);<sp/>});<sp/></highlight></codeline>
<codeline><highlight class="normal">B.<ref refid="classtf_1_1FlowBuilder_1a60d7a666cab71ecfa3010b2efb0d6b57" kindref="member">emplace</ref>([](){<sp/>printf(</highlight><highlight class="stringliteral">"Taskflow<sp/>B\n"</highlight><highlight class="normal">);<sp/>});<sp/></highlight></codeline>
<codeline><highlight class="normal">C.<ref refid="classtf_1_1FlowBuilder_1a60d7a666cab71ecfa3010b2efb0d6b57" kindref="member">emplace</ref>([](){<sp/><ref refid="cpp/io/c/fprintf" kindref="compound" external="/Users/twhuang/Code/taskflow/doxygen/cppreference-doxygen-web.tag.xml">printf</ref>(</highlight><highlight class="stringliteral">"Taskflow<sp/>C\n"</highlight><highlight class="normal">);<sp/>});<sp/></highlight></codeline>
<codeline><highlight class="normal">D.<ref refid="classtf_1_1FlowBuilder_1a60d7a666cab71ecfa3010b2efb0d6b57" kindref="member">emplace</ref>([](){<sp/><ref refid="cpp/io/c/fprintf" kindref="compound" external="/Users/twhuang/Code/taskflow/doxygen/cppreference-doxygen-web.tag.xml">printf</ref>(</highlight><highlight class="stringliteral">"Taskflow<sp/>D\n"</highlight><highlight class="normal">);<sp/>});<sp/></highlight></codeline>
<codeline><highlight class="normal"></highlight></codeline>
<codeline><highlight class="normal"></highlight><highlight class="keyword">auto</highlight><highlight class="normal"><sp/>TA<sp/>=<sp/>executor.<ref refid="classtf_1_1Executor_1a0e2d792f28136b8227b413d0c27d5c7f" kindref="member">silent_dependent_async</ref>(<ref refid="namespacetf_1a6c73f8957e0f60c76614243979e3b112" kindref="member">tf::make_module_task</ref>(A));</highlight></codeline>
<codeline><highlight class="normal"></highlight><highlight class="keyword">auto</highlight><highlight class="normal"><sp/>TB<sp/>=<sp/>executor.<ref refid="classtf_1_1Executor_1a0e2d792f28136b8227b413d0c27d5c7f" kindref="member">silent_dependent_async</ref>(<ref refid="namespacetf_1a6c73f8957e0f60c76614243979e3b112" kindref="member">tf::make_module_task</ref>(B),<sp/>TA);</highlight></codeline>
<codeline><highlight class="normal"></highlight><highlight class="keyword">auto</highlight><highlight class="normal"><sp/>TC<sp/>=<sp/>executor.<ref refid="classtf_1_1Executor_1a0e2d792f28136b8227b413d0c27d5c7f" kindref="member">silent_dependent_async</ref>(<ref refid="namespacetf_1a6c73f8957e0f60c76614243979e3b112" kindref="member">tf::make_module_task</ref>(C),<sp/>TB);</highlight></codeline>
<codeline><highlight class="normal"></highlight><highlight class="keyword">auto</highlight><highlight class="normal"><sp/>[TD,<sp/>FD]<sp/>=<sp/>executor.<ref refid="classtf_1_1Executor_1aee02b63d3a91ad5ca5a1c0e71f3e128f" kindref="member">dependent_async</ref>(<ref refid="namespacetf_1a6c73f8957e0f60c76614243979e3b112" kindref="member">tf::make_module_task</ref>(D),<sp/>TC);</highlight></codeline>
<codeline><highlight class="normal">FD.get();</highlight></codeline>
</programlisting></para>
<para><dotfile name="module_task_2.dot"></dotfile>
</para>
<para><programlisting filename=".bash"><codeline><highlight class="normal">#<sp/>dependent-async<sp/>tasks<sp/>enforce<sp/>a<sp/>sequential<sp/>execution<sp/>of<sp/>the<sp/>four<sp/>taskflows</highlight></codeline>
<codeline><highlight class="normal">Taskflow<sp/>A</highlight></codeline>
<codeline><highlight class="normal">Taskflow<sp/>B</highlight></codeline>
<codeline><highlight class="normal">Taskflow<sp/>C</highlight></codeline>
<codeline><highlight class="normal">Taskflow<sp/>D</highlight></codeline>
</programlisting></para>
<para>The module task maker, <ref refid="namespacetf_1a6c73f8957e0f60c76614243979e3b112" kindref="member">tf::make_module_task</ref>, operates similarly to <ref refid="classtf_1_1FlowBuilder_1ac6f22228d4c2ea2e643c4b0d42c0e92a" kindref="member">tf::Taskflow::composed_of</ref>, but provides a more general interface that can be used beyond Taskflow. Specifically, the following two approaches achieve equivalent functionality:</para>
<para><programlisting filename=".cpp"><codeline><highlight class="comment">//<sp/>approach<sp/>1:<sp/>composition<sp/>using<sp/>composed_of</highlight><highlight class="normal"></highlight></codeline>
<codeline><highlight class="normal"><ref refid="classtf_1_1Task" kindref="compound">tf::Task</ref><sp/>m1<sp/>=<sp/>taskflow1.<ref refid="classtf_1_1Task_1ab38be520fe700cb4ca1f312308a95585" kindref="member">composed_of</ref>(taskflow2);</highlight></codeline>
<codeline><highlight class="normal"></highlight></codeline>
<codeline><highlight class="normal"></highlight><highlight class="comment">//<sp/>approach<sp/>2:<sp/>composition<sp/>using<sp/>make_module_task</highlight><highlight class="normal"></highlight></codeline>
<codeline><highlight class="normal"><ref refid="classtf_1_1Task" kindref="compound">tf::Task</ref><sp/>m1<sp/>=<sp/>taskflow1.emplace(<ref refid="namespacetf_1a6c73f8957e0f60c76614243979e3b112" kindref="member">tf::make_module_task</ref>(taskflow2));</highlight></codeline>
</programlisting></para>
<para><simplesect kind="attention"><para>Similar to <ref refid="classtf_1_1FlowBuilder_1ac6f22228d4c2ea2e643c4b0d42c0e92a" kindref="member">tf::Taskflow::composed_of</ref>, <ref refid="namespacetf_1a6c73f8957e0f60c76614243979e3b112" kindref="member">tf::make_module_task</ref> does not assume ownership of the provided taskflow but a soft reference. You are responsible for ensuring that the encapsulated taskflow remains valid throughout its execution.</para>
</simplesect>
</para>
</sect1>
<sect1 id="ModuleAlgorithm_1CreateAModuleTaskOverACustomGraph">
<title>Create a Module Task over a Custom Graph</title><para>In addition to encapsulate taskflow graphs, you can create a module task to schedule a custom graph target. A schedulable target (of type <computeroutput>T</computeroutput>) must define the method <computeroutput>T::graph()</computeroutput> that returns a reference to the <ref refid="classtf_1_1Graph" kindref="compound">tf::Graph</ref> object managed by <computeroutput>T</computeroutput>. The following example defines a custom graph that can be scheduled through making module tasks:</para>
<para><programlisting filename=".cpp"><codeline><highlight class="keyword">struct<sp/></highlight><highlight class="normal">CustomGraph<sp/>{</highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/><ref refid="classtf_1_1Graph" kindref="compound">tf::Graph</ref><sp/>graph;</highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/>CustomGraph()<sp/>{</highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/><sp/><sp/></highlight><highlight class="comment">//<sp/>use<sp/>flow<sp/>builder<sp/>to<sp/>inherit<sp/>all<sp/>task<sp/>creation<sp/>methods<sp/>in<sp/>tf::Taskflow</highlight><highlight class="normal"></highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/><sp/><sp/><ref refid="classtf_1_1FlowBuilder" kindref="compound">tf::FlowBuilder</ref><sp/>builder(graph);</highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/><sp/><sp/><ref refid="classtf_1_1Task" kindref="compound">tf::Task</ref><sp/>task<sp/>=<sp/>builder.emplace([](){</highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/><sp/><sp/><sp/><sp/><ref refid="cpp/io/basic_ostream" kindref="compound" external="/Users/twhuang/Code/taskflow/doxygen/cppreference-doxygen-web.tag.xml">std::cout</ref><sp/><<<sp/></highlight><highlight class="stringliteral">"a<sp/>task\n"</highlight><highlight class="normal">;<sp/><sp/></highlight><highlight class="comment">//<sp/>static<sp/>task</highlight><highlight class="normal"></highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/><sp/><sp/>});</highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/>}</highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/></highlight><highlight class="comment">//<sp/>returns<sp/>a<sp/>reference<sp/>to<sp/>the<sp/>graph<sp/>for<sp/>taskflow<sp/>composition</highlight><highlight class="normal"></highlight></codeline>
<codeline><highlight class="normal"><sp/><sp/>Graph&<sp/>graph()<sp/>{<sp/></highlight><highlight class="keywordflow">return</highlight><highlight class="normal"><sp/>graph;<sp/>}</highlight></codeline>
<codeline><highlight class="normal">};</highlight></codeline>
<codeline><highlight class="normal"></highlight></codeline>
<codeline><highlight class="normal">CustomGraph<sp/>target;</highlight></codeline>
<codeline><highlight class="normal">executor.<ref refid="classtf_1_1Executor_1af960048056f7c6b5bc71f4f526f05df7" kindref="member">async</ref>(<ref refid="namespacetf_1a6c73f8957e0f60c76614243979e3b112" kindref="member">tf::make_module_task</ref>(target));</highlight></codeline>
</programlisting></para>
<para><simplesect kind="attention"><para>Users are responsible for ensuring the given custom graph remains valid throughout its execution. The executor does not assume ownership of the custom graph. </para>
</simplesect>
</para>
</sect1>
</detaileddescription>
<location file="doxygen/algorithms/module.dox"/>
</compounddef>
</doxygen>