@@ -21,11 +21,14 @@ use crate::split_at::SplitPreference;
21
21
#[ derive( Copy , Clone , Debug ) ]
22
22
pub struct Parallel < I > {
23
23
iter : I ,
24
+ min_len : usize ,
24
25
}
25
26
27
+ const DEFAULT_MIN_LEN : usize = 1 ;
28
+
26
29
/// Parallel producer wrapper.
27
30
#[ derive( Copy , Clone , Debug ) ]
28
- struct ParallelProducer < I > ( I ) ;
31
+ struct ParallelProducer < I > ( I , usize ) ;
29
32
30
33
macro_rules! par_iter_wrapper {
31
34
// thread_bounds are either Sync or Send + Sync
@@ -40,6 +43,7 @@ macro_rules! par_iter_wrapper {
40
43
fn into_par_iter( self ) -> Self :: Iter {
41
44
Parallel {
42
45
iter: self ,
46
+ min_len: DEFAULT_MIN_LEN ,
43
47
}
44
48
}
45
49
}
@@ -67,7 +71,7 @@ macro_rules! par_iter_wrapper {
67
71
fn with_producer<Cb >( self , callback: Cb ) -> Cb :: Output
68
72
where Cb : ProducerCallback <Self :: Item >
69
73
{
70
- callback. callback( ParallelProducer ( self . iter) )
74
+ callback. callback( ParallelProducer ( self . iter, self . min_len ) )
71
75
}
72
76
73
77
fn len( & self ) -> usize {
@@ -106,7 +110,7 @@ macro_rules! par_iter_wrapper {
106
110
107
111
fn split_at( self , i: usize ) -> ( Self , Self ) {
108
112
let ( a, b) = self . 0 . split_at( i) ;
109
- ( ParallelProducer ( a) , ParallelProducer ( b) )
113
+ ( ParallelProducer ( a, self . 1 ) , ParallelProducer ( b, self . 1 ) )
110
114
}
111
115
}
112
116
@@ -131,11 +135,11 @@ macro_rules! par_iter_view_wrapper {
131
135
fn into_par_iter( self ) -> Self :: Iter {
132
136
Parallel {
133
137
iter: self ,
138
+ min_len: DEFAULT_MIN_LEN ,
134
139
}
135
140
}
136
141
}
137
142
138
-
139
143
impl <' a, A , D > ParallelIterator for Parallel <$view_name<' a, A , D >>
140
144
where D : Dimension ,
141
145
A : $( $thread_bounds) * ,
@@ -144,28 +148,47 @@ macro_rules! par_iter_view_wrapper {
144
148
fn drive_unindexed<C >( self , consumer: C ) -> C :: Result
145
149
where C : UnindexedConsumer <Self :: Item >
146
150
{
147
- bridge_unindexed( ParallelProducer ( self . iter) , consumer)
151
+ bridge_unindexed( ParallelProducer ( self . iter, self . min_len ) , consumer)
148
152
}
149
153
150
154
fn opt_len( & self ) -> Option <usize > {
151
155
None
152
156
}
153
157
}
154
158
159
+ impl <' a, A , D > Parallel <$view_name<' a, A , D >>
160
+ where D : Dimension ,
161
+ A : $( $thread_bounds) * ,
162
+ {
163
+ /// Sets the minimum number of elements desired to process in each job. This will not be
164
+ /// split any smaller than this length, but of course a producer could already be smaller
165
+ /// to begin with.
166
+ ///
167
+ /// ***Panics*** if `min_len` is zero.
168
+ pub fn with_min_len( self , min_len: usize ) -> Self {
169
+ assert_ne!( min_len, 0 , "Minimum number of elements must at least be one to avoid splitting off empty tasks." ) ;
170
+
171
+ Self {
172
+ min_len,
173
+ ..self
174
+ }
175
+ }
176
+ }
177
+
155
178
impl <' a, A , D > UnindexedProducer for ParallelProducer <$view_name<' a, A , D >>
156
179
where D : Dimension ,
157
180
A : $( $thread_bounds) * ,
158
181
{
159
182
type Item = <$view_name<' a, A , D > as IntoIterator >:: Item ;
160
183
fn split( self ) -> ( Self , Option <Self >) {
161
- if self . 0 . len( ) <= 1 {
184
+ if self . 0 . len( ) <= self . 1 {
162
185
return ( self , None )
163
186
}
164
187
let array = self . 0 ;
165
188
let max_axis = array. max_stride_axis( ) ;
166
189
let mid = array. len_of( max_axis) / 2 ;
167
190
let ( a, b) = array. split_at( max_axis, mid) ;
168
- ( ParallelProducer ( a) , Some ( ParallelProducer ( b) ) )
191
+ ( ParallelProducer ( a, self . 1 ) , Some ( ParallelProducer ( b, self . 1 ) ) )
169
192
}
170
193
171
194
fn fold_with<F >( self , folder: F ) -> F
@@ -217,6 +240,7 @@ macro_rules! zip_impl {
217
240
fn into_par_iter( self ) -> Self :: Iter {
218
241
Parallel {
219
242
iter: self ,
243
+ min_len: DEFAULT_MIN_LEN ,
220
244
}
221
245
}
222
246
}
@@ -233,7 +257,7 @@ macro_rules! zip_impl {
233
257
fn drive_unindexed<Cons >( self , consumer: Cons ) -> Cons :: Result
234
258
where Cons : UnindexedConsumer <Self :: Item >
235
259
{
236
- bridge_unindexed( ParallelProducer ( self . iter) , consumer)
260
+ bridge_unindexed( ParallelProducer ( self . iter, self . min_len ) , consumer)
237
261
}
238
262
239
263
fn opt_len( & self ) -> Option <usize > {
@@ -251,11 +275,11 @@ macro_rules! zip_impl {
251
275
type Item = ( $( $p:: Item , ) * ) ;
252
276
253
277
fn split( self ) -> ( Self , Option <Self >) {
254
- if ! self . 0 . can_split ( ) {
278
+ if self . 0 . size ( ) <= self . 1 {
255
279
return ( self , None )
256
280
}
257
281
let ( a, b) = self . 0 . split( ) ;
258
- ( ParallelProducer ( a) , Some ( ParallelProducer ( b) ) )
282
+ ( ParallelProducer ( a, self . 1 ) , Some ( ParallelProducer ( b, self . 1 ) ) )
259
283
}
260
284
261
285
fn fold_with<Fold >( self , folder: Fold ) -> Fold
@@ -284,6 +308,25 @@ zip_impl! {
284
308
[ P1 P2 P3 P4 P5 P6 ] ,
285
309
}
286
310
311
+ impl < D , Parts > Parallel < Zip < Parts , D > >
312
+ where
313
+ D : Dimension ,
314
+ {
315
+ /// Sets the minimum number of elements desired to process in each job. This will not be
316
+ /// split any smaller than this length, but of course a producer could already be smaller
317
+ /// to begin with.
318
+ ///
319
+ /// ***Panics*** if `min_len` is zero.
320
+ pub fn with_min_len ( self , min_len : usize ) -> Self {
321
+ assert_ne ! ( min_len, 0 , "Minimum number of elements must at least be one to avoid splitting off empty tasks." ) ;
322
+
323
+ Self {
324
+ min_len,
325
+ ..self
326
+ }
327
+ }
328
+ }
329
+
287
330
/// A parallel iterator (unindexed) that produces the splits of the array
288
331
/// or producer `P`.
289
332
pub ( crate ) struct ParallelSplits < P > {
0 commit comments