db089fe6dfb68859387f09a05eb9cc002a1b7d30
[folly.git] / folly / gen / Parallel.h
1 /*
2  * Copyright 2017 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #pragma once
18 #define FOLLY_GEN_PARALLEL_H_
19
20 #include <mutex>
21
22 #include <folly/gen/Base.h>
23
24 namespace folly {
25 namespace gen {
26 namespace detail {
27
28 template <class Ops>
29 class Parallel;
30
31 template <class Sink>
32 class Sub;
33
34 template <class Iterator>
35 class ChunkedRangeSource;
36
37 }
38
39 /**
40  * chunked() - For producing values from a container in slices.
41  *
42  * Especially for use with 'parallel()', chunked can be used to process values
43  * from a persistent container in chunks larger than one value at a time. The
44  * values produced are generators for slices of the input container. */
45 template <
46     class Container,
47     class Iterator = typename Container::const_iterator,
48     class Chunked = detail::ChunkedRangeSource<Iterator>>
49 Chunked chunked(const Container& container, int chunkSize = 256) {
50   return Chunked(chunkSize, folly::range(container.begin(), container.end()));
51 }
52
53 template <
54     class Container,
55     class Iterator = typename Container::iterator,
56     class Chunked = detail::ChunkedRangeSource<Iterator>>
57 Chunked chunked(Container& container, int chunkSize = 256) {
58   return Chunked(chunkSize, folly::range(container.begin(), container.end()));
59 }
60
61
62 /**
63  * parallel - A parallelization operator.
64  *
65  * 'parallel(ops)' can be used with any generator to process a segment
66  * of the pipeline in parallel. Multiple threads are used to apply the
67  * operations ('ops') to the input sequence, with the resulting sequence
68  * interleaved to be processed on the client thread.
69  *
70  *   auto scoredResults
71  *     = from(ids)
72  *     | parallel(map(fetchObj) | filter(isValid) | map(scoreObj))
73  *     | as<vector>();
74  *
75  * Operators specified for parallel execution must yield sequences, not just
76  * individual values. If a sink function such as 'count' is desired, it must be
77  * wrapped in 'sub' to produce a subcount, since any such aggregation must be
78  * re-aggregated.
79  *
80  *   auto matches
81  *     = from(docs)
82  *     | parallel(filter(expensiveTest) | sub(count))
83  *     | sum;
84  *
85  * Here, each thread counts its portion of the result, then the sub-counts are
86  * summed up to produce the total count.
87  */
88 template <class Ops, class Parallel = detail::Parallel<Ops>>
89 Parallel parallel(Ops ops, size_t threads = 0) {
90   return Parallel(std::move(ops), threads);
91 }
92
93 /**
94  * sub - For sub-summarization of a sequence.
95  *
96  * 'sub' can be used to apply a sink function to a generator, but wrap the
97  * single value in another generator. Note that the sink is eagerly evaluated on
98  * the input sequence.
99  *
100  *   auto sum = from(list) | sub(count) | first;
101  *
102  * This is primarily used with 'parallel', as noted above.
103  */
104 template <class Sink, class Sub = detail::Sub<Sink>>
105 Sub sub(Sink sink) {
106   return Sub(std::move(sink));
107 }
108 } // !namespace gen
109 } // !namespace folly
110
111 #include <folly/gen/Parallel-inl.h>