166 lines
4.7 KiB
Text
166 lines
4.7 KiB
Text
namespace tf {
|
|
|
|
/** @page ParallelTransforms Parallel Transforms
|
|
|
|
%Taskflow provides template functions for constructing tasks to
|
|
perform parallel transforms over ranges of items.
|
|
|
|
@tableofcontents
|
|
|
|
@section ParallelTransformsInclude Include the Header
|
|
|
|
You need to include the header file, <tt>taskflow/algorithm/transform.hpp</tt>,
|
|
for creating a parallel-transform task.
|
|
|
|
@code{.cpp}
|
|
#include <taskflow/algorithm/transform.hpp>
|
|
@endcode
|
|
|
|
@section ParallelTransformsOverARange Create a Unary Parallel-Transform Task
|
|
|
|
Parallel-transform transforms a range of items, possibly
|
|
with a different type for the transformed data, and stores the result in another range.
|
|
The task created by tf::Taskflow::transform(B first1, E last1, O d_first, C c, P&& part)
|
|
is equivalent to a parallel execution of the following loop:
|
|
|
|
@code{.cpp}
|
|
while (first1 != last1) {
|
|
*d_first++ = c(*first1++);
|
|
}
|
|
@endcode
|
|
|
|
tf::Taskflow::transform
|
|
simultaneously applies the callable @c c to the object obtained by dereferencing
|
|
every iterator in the range <tt>[first1, last1)</tt> and stores
|
|
the result in another range beginning at @c d_first.
|
|
It is user's responsibility for ensuring the range is valid
|
|
within the execution of the parallel-transform task.
|
|
|
|
@code{.cpp}
|
|
std::vector<int> src = {1, 2, 3, 4, 5};
|
|
std::vector<int> tgt(src.size());
|
|
taskflow.transform(src.begin(), src.end(), tgt.begin(), [](int i){
|
|
std::cout << "transforming item " << i << " to " << i + 1 << '\n';
|
|
return i + 1;
|
|
});
|
|
@endcode
|
|
|
|
@section ParallelTransformsCaptureIteratorsByReference Capture Iterators by Reference
|
|
|
|
You can pass iterators by reference using @std_ref
|
|
to marshal parameter update between dependent tasks.
|
|
This is especially useful when the range is unknown
|
|
at the time of creating a parallel-transform task,
|
|
but needs initialization from another task.
|
|
|
|
@code{.cpp}
|
|
std::vector<int> src, tgt;
|
|
std::vector<int>::iterator first, last, d_first;
|
|
|
|
tf::Task init = taskflow.emplace([&](){
|
|
src.resize(1000);
|
|
tgt.resize(1000);
|
|
first = src.begin();
|
|
last = src.end();
|
|
d_first = tgt.begin();
|
|
});
|
|
|
|
tf::Task transform = taskflow.transform(
|
|
std::ref(first), std::ref(last), std::ref(d_first),
|
|
[&](int i) {
|
|
std::cout << "transforming item " << i << " to " << i + 1 << '\n';
|
|
return i+1;
|
|
}
|
|
);
|
|
|
|
init.precede(transform);
|
|
@endcode
|
|
|
|
When @c init finishes, the parallel-transform task @c transform
|
|
will see @c first pointing to the beginning of @c src and
|
|
@c last pointing to the end of @c src.
|
|
Then, it simultaneously transforms these 1000 items
|
|
by adding one to each element and stores the result
|
|
in another range starting at @c d_first.
|
|
|
|
@section ParallelBinaryTransformsOverARange Create a Binary Parallel-Transform Task
|
|
|
|
You can use the overload,
|
|
tf::Taskflow::transform(B1 first1, E1 last1, B2 first2, O d_first, C c, P&& part),
|
|
to perform parallel transforms on two source ranges pointed by
|
|
@c first1 and @c first2 using the binary
|
|
operator @c c
|
|
and store the result in another range pointed by @c d_first.
|
|
This method is equivalent to the parallel execution of the following loop:
|
|
|
|
@code{.cpp}
|
|
while (first1 != last1) {
|
|
*d_first++ = c(*first1++, *first2++);
|
|
}
|
|
@endcode
|
|
|
|
The following example creates a parallel-transform task
|
|
that adds two ranges of elements one by one
|
|
and stores the result in a target range:
|
|
|
|
@code{.cpp}
|
|
std::vector<int> src1 = {1, 2, 3, 4, 5};
|
|
std::vector<int> src2 = {5, 4, 3, 2, 1};
|
|
std::vector<int> tgt(src1.size());
|
|
taskflow.transform(
|
|
src1.begin(), src1.end(), src2.begin(), tgt.begin(),
|
|
[](int i, int j){
|
|
return i + j;
|
|
}
|
|
);
|
|
@endcode
|
|
|
|
@section ParallelTransformsCfigureAPartitioner Configure a Partitioner
|
|
|
|
You can configure a partitioner for parallel-transform tasks to run with different
|
|
scheduling methods, such as guided partitioning, dynamic partitioning, and static partitioning.
|
|
The following example creates two parallel-transform tasks using two different
|
|
partitioners, one with the static partitioning algorithm and
|
|
another one with the guided partitioning algorithm:
|
|
|
|
@code{.cpp}
|
|
tf::StaticPartitioner static_partitioner;
|
|
tf::GuidedPartitioner guided_partitioner;
|
|
|
|
std::vector<int> src1 = {1, 2, 3, 4, 5};
|
|
std::vector<int> src2 = {5, 4, 3, 2, 1};
|
|
std::vector<int> tgt1(src1.size());
|
|
std::vector<int> tgt2(src2.size());
|
|
|
|
// create a parallel-transform task with static execution partitioner
|
|
taskflow.transform(
|
|
src1.begin(), src1.end(), src2.begin(), tgt1.begin(),
|
|
[](int i, int j){
|
|
return i + j;
|
|
},
|
|
static_partitioner
|
|
);
|
|
|
|
// create a parallel-transform task with guided execution partitioner
|
|
taskflow.transform(
|
|
src1.begin(), src1.end(), src2.begin(), tgt2.begin(),
|
|
[](int i, int j){
|
|
return i + j;
|
|
},
|
|
guided_partitioner
|
|
);
|
|
@endcode
|
|
|
|
@note
|
|
By default, parallel-transform tasks use tf::DefaultPartitioner
|
|
if no partitioner is specified.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|