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
128 lines (128 loc) · 17.3 KB
/
Copy pathModuleAlgorithm.xml
File metadata and controls
128 lines (128 loc) · 17.3 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
<?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 generic setting, the template function, <ref refid="namespacetf_1ad13f8d0b6628d895792570515497139c" 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 way to encapsulate and reuse complex task logic within your Taskflow applications. The example below demonstrates how to create and launch multiple taskflows in parallel using asynchronous tasking:</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="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">executor.<ref refid="classtf_1_1Executor_1af960048056f7c6b5bc71f4f526f05df7" kindref="member">async</ref>(<ref refid="namespacetf_1ad13f8d0b6628d895792570515497139c" kindref="member">tf::make_module_task</ref>(A));</highlight></codeline>
<codeline><highlight class="normal">executor.<ref refid="classtf_1_1Executor_1af960048056f7c6b5bc71f4f526f05df7" kindref="member">async</ref>(<ref refid="namespacetf_1ad13f8d0b6628d895792570515497139c" kindref="member">tf::make_module_task</ref>(B));</highlight></codeline>
<codeline><highlight class="normal">executor.<ref refid="classtf_1_1Executor_1af960048056f7c6b5bc71f4f526f05df7" kindref="member">async</ref>(<ref refid="namespacetf_1ad13f8d0b6628d895792570515497139c" kindref="member">tf::make_module_task</ref>(C));</highlight></codeline>
<codeline><highlight class="normal">executor.<ref refid="classtf_1_1Executor_1af960048056f7c6b5bc71f4f526f05df7" kindref="member">async</ref>(<ref refid="namespacetf_1ad13f8d0b6628d895792570515497139c" kindref="member">tf::make_module_task</ref>(D));</highlight></codeline>
<codeline><highlight class="normal">executor.<ref refid="classtf_1_1Executor_1ab9aa252f70e9a40020a1e5a89d485b85" kindref="member">wait_for_all</ref>();<sp/><sp/></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=".shell-session"><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_1ad13f8d0b6628d895792570515497139c" 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_1ad13f8d0b6628d895792570515497139c" 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_1ad13f8d0b6628d895792570515497139c" 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_1ad13f8d0b6628d895792570515497139c" 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=".shell-session"><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_1ad13f8d0b6628d895792570515497139c" kindref="member">tf::make_module_task</ref>, functions basically similar to <ref refid="classtf_1_1FlowBuilder_1ac6f22228d4c2ea2e643c4b0d42c0e92a" kindref="member">tf::Taskflow::composed_of</ref> but provides a more generic interface that can be used beyond Taskflow. Specifically, the following two approaches achieve the same 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_1ad13f8d0b6628d895792570515497139c" 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_1ad13f8d0b6628d895792570515497139c" 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_1ad13f8d0b6628d895792570515497139c" 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>