2017
[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 { namespace gen {
25 namespace detail {
26
27 template <class Ops>
28 class Parallel;
29
30 template <class Sink>
31 class Sub;
32
33 template <class Iterator>
34 class ChunkedRangeSource;
35
36 }
37
38 /**
39  * chunked() - For producing values from a container in slices.
40  *
41  * Especially for use with 'parallel()', chunked can be used to process values
42  * from a persistent container in chunks larger than one value at a time. The
43  * values produced are generators for slices of the input container. */
44 template <class Container,
45           class Iterator = typename Container::const_iterator,
46           class Chunked = detail::ChunkedRangeSource<Iterator>>
47 Chunked chunked(const Container& container, int chunkSize = 256) {
48   return Chunked(chunkSize, folly::range(container.begin(), container.end()));
49 }
50
51 template <class Container,
52           class Iterator = typename Container::iterator,
53           class Chunked = detail::ChunkedRangeSource<Iterator>>
54 Chunked chunked(Container& container, int chunkSize = 256) {
55   return Chunked(chunkSize, folly::range(container.begin(), container.end()));
56 }
57
58
59 /**
60  * parallel - A parallelization operator.
61  *
62  * 'parallel(ops)' can be used with any generator to process a segment
63  * of the pipeline in parallel. Multiple threads are used to apply the
64  * operations ('ops') to the input sequence, with the resulting sequence
65  * interleaved to be processed on the client thread.
66  *
67  *   auto scoredResults
68  *     = from(ids)
69  *     | parallel(map(fetchObj) | filter(isValid) | map(scoreObj))
70  *     | as<vector>();
71  *
72  * Operators specified for parallel execution must yield sequences, not just
73  * individual values. If a sink function such as 'count' is desired, it must be
74  * wrapped in 'sub' to produce a subcount, since any such aggregation must be
75  * re-aggregated.
76  *
77  *   auto matches
78  *     = from(docs)
79  *     | parallel(filter(expensiveTest) | sub(count))
80  *     | sum;
81  *
82  * Here, each thread counts its portion of the result, then the sub-counts are
83  * summed up to produce the total count.
84  */
85 template <class Ops, class Parallel = detail::Parallel<Ops>>
86 Parallel parallel(Ops ops, size_t threads = 0) {
87   return Parallel(std::move(ops), threads);
88 }
89
90 /**
91  * sub - For sub-summarization of a sequence.
92  *
93  * 'sub' can be used to apply a sink function to a generator, but wrap the
94  * single value in another generator. Note that the sink is eagerly evaluated on
95  * the input sequence.
96  *
97  *   auto sum = from(list) | sub(count) | first;
98  *
99  * This is primarily used with 'parallel', as noted above.
100  */
101 template <class Sink, class Sub = detail::Sub<Sink>>
102 Sub sub(Sink sink) {
103   return Sub(std::move(sink));
104 }
105
106 }} // !namespace folly::gen
107
108 #include <folly/gen/Parallel-inl.h>