ParallelReduction Parallel Reduction Include the Header ParallelReduction_1ParallelReductionInclude Create a Parallel-Reduction Task ParallelReduction_1A2ParallelReduction Capture Iterators by Reference ParallelReduction_1ParallelReductionCaptureIteratorsByReference Create a Parallel-Transform-Reduction Task ParallelReduction_1A2ParallelTransformationReduction Configure a Partitioner ParallelReduction_1ParallelReductionCfigureAPartitioner Taskflow provides template function that constructs a task to perform parallel reduction over a range of items. Include the Header You need to include the header file, taskflow/algorithm/reduce.hpp, for creating a parallel-reduction task. #include<taskflow/algorithm/reduce.hpp> Create a Parallel-Reduction Task The reduction task created by tf::Taskflow::reduce(B first, E last, T& result, O bop, P&& part) performs parallel reduction over a range of elements specified by [first, last) using the binary operator bop and stores the reduced result in result. It represents the parallel execution of the following reduction loop: for(autoitr=first;itr<last;itr++){ result=bop(result,*itr); } At runtime, the reduction task spawns a subflow to perform parallel reduction. The reduced result is stored in result that will be captured by reference in the reduction task. It is your responsibility to ensure result remains alive during the parallel execution. intsum=100; std::vector<int>vec={1,2,3,4,5,6,7,8,9,10}; tf::Tasktask=taskflow.reduce(vec.begin(),vec.end(),sum, [](intl,intr){returnl+r;}//binaryreduceroperator ); executor.run(taskflow).wait(); assert(sum==100+55); The order in which the binary operator is applied to pairs of elements is unspecified. In other words, the elements of the range may be grouped and rearranged in arbitrary order. The result and the argument types of the binary operator must be consistent with the input data type. 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-reduction task, but needs initialization from another task. intsum=100; std::vector<int>vec; std::vector<int>::iteratorfirst,last; tf::Taskinit=taskflow.emplace([&](){ vec={1,2,3,4,5,6,7,8,9,10}; first=vec.begin(); last=vec.end(); }); tf::Tasktask=taskflow.reduce(std::ref(first),std::ref(last),sum, [](intl,intr){returnl+r;}//binaryreduceroperator ); //wrong!mustusestd::ref,orfirstandlastarecapturedbycopy //tf::Tasktask=taskflow.reduce(first,last,sum,[](intl,intr){ //returnl+r;//binaryreduceroperator //}); init.precede(task); executor.run(taskflow).wait(); assert(sum==100+55); In the above example, when init finishes, vec has been initialized to 10 elements with first and last pointing to the data range of vec. The reduction task will then work on this initialized range as a result of passing iterators by reference. Create a Parallel-Transform-Reduction Task It is common to transform each element into a new data type and then perform reduction on the transformed elements. Taskflow provides a method, tf::Taskflow::transform_reduce(B first, E last, T& result, BOP bop, UOP uop, P&& part), that applies uop to transform each element in the specified range and then perform parallel reduction over result and transformed elements. It represents the parallel execution of the following reduction loop: for(autoitr=first;itr<last;itr++){ result=bop(result,uop(*itr)); } The example below transforms each digit in a string to an integer number and then sums up all integers in parallel. std::stringstr="12345678"; intsum{0}; tf::Tasktask=taskflow.transform_reduce(str.begin(),str.end(),sum, [](inta,intb){//binaryreductionoperator returna+b; }, [](charc)->int{//unarytransformationoperator returnc-'0'; } ); executor.run(taskflow).wait(); assert(sum==1+2+3+4+5+6+7+8);//sumwillbe36 The order in which we apply the binary operator on the transformed elements is unspecified. It is possible that the binary operator will take r-value in both arguments, for example, bop(uop(*itr1), uop(*itr2)), due to the transformed temporaries. When data passing is expensive, you may define the result type T to be move-constructible. Configure a Partitioner You can configure a partitioner for parallel-reduction tasks to run with different scheduling methods, such as guided partitioning, dynamic partitioning, and static partitioning. The following example creates two parallel-reduction tasks using two different partitioners, one with the static partitioning algorithm and another one with the guided partitioning algorithm: tf::StaticPartitionerstatic_partitioner; tf::GuidedPartitionerguided_partitioner; intsum1=100,sum2=100; std::vector<int>vec={1,2,3,4,5,6,7,8,9,10}; //createaparallel-reductiontaskwithstaticpartitioner taskflow.reduce(vec.begin(),vec.end(),sum1, [](intl,intr){returnl+r;}, static_partitioner ); //createaparallel-reductiontaskwithguidedpartitioner taskflow.reduce(vec.begin(),vec.end(),sum2, [](intl,intr){returnl+r;}, guided_partitioner ); By default, parallel-reduction tasks use tf::DefaultPartitioner if no partitioner is specified.