ParallelOpportunistic.cs
Go to the documentation of this file.
1 using System;
4 using System.Threading;
6 
7 namespace SpicyPixel.Threading
8 {
29  public static class ParallelOpportunistic
30  {
31  static readonly ParallelOptions ParallelOptionsDefault = new ParallelOptions ();
32 
33  static bool supportsParallelism = true;
34 
39  public static bool SupportsParallelism {
40  get {
41  return supportsParallelism;
42  }
43  set {
44  supportsParallelism = value;
45  }
46  }
47 
48  #region For
49  public static ParallelLoopResult For (int fromInclusive, int toExclusive, Action<int> body)
56  {
57  return For (fromInclusive, toExclusive, ParallelOptionsDefault, body);
58  }
59 
66  public static ParallelLoopResult For (int fromInclusive, int toExclusive, Action<int, ParallelLoopState> body)
67  {
68  return For (fromInclusive, toExclusive, ParallelOptionsDefault, body);
69  }
70 
78  public static ParallelLoopResult For (int fromInclusive, int toExclusive, ParallelOptions parallelOptions, Action<int> body)
79  {
80  return For (fromInclusive, toExclusive, parallelOptions, (index, state) => body (index));
81  }
82 
90  public static ParallelLoopResult For (int fromInclusive, int toExclusive, ParallelOptions parallelOptions, Action<int, ParallelLoopState> body)
91  {
92  return For<object> (fromInclusive, toExclusive, parallelOptions, () => null, (i, s, l) => { body (i, s); return null; }, _ => { });
93  }
94 
104  public static ParallelLoopResult For<TLocal> (int fromInclusive,
105  int toExclusive,
106  Func<TLocal> localInit,
107  Func<int, ParallelLoopState, TLocal, TLocal> body,
108  Action<TLocal> localFinally)
109  {
110  return For<TLocal> (fromInclusive, toExclusive, ParallelOptionsDefault, localInit, body, localFinally);
111  }
112 
123  public static ParallelLoopResult For<TLocal> (int fromInclusive,
124  int toExclusive,
125  ParallelOptions parallelOptions,
126  Func<TLocal> localInit,
127  Func<int, ParallelLoopState, TLocal, TLocal> body,
128  Action<TLocal> localFinally)
129  {
130  if (SupportsParallelism) {
131  return Parallel.For (fromInclusive, toExclusive, parallelOptions, localInit, body, localFinally);
132  }
133 
134  if (body == null)
135  throw new ArgumentNullException ("body");
136  if (localInit == null)
137  throw new ArgumentNullException ("localInit");
138  if (localFinally == null)
139  throw new ArgumentNullException ("localFinally");
140  if (parallelOptions == null)
141  throw new ArgumentNullException ("options");
142  if (fromInclusive >= toExclusive)
143  return new ParallelLoopResult (null, true);
144 
146 
147  TLocal local = localInit ();
148 
149  ParallelLoopState state = new ParallelLoopState (infos);
150  CancellationToken token = parallelOptions.CancellationToken;
151 
152  try {
153  for (int i = fromInclusive; i < toExclusive; ++i) {
154  if (infos.IsStopped)
155  break;
156 
158 
159  if (infos.LowestBreakIteration != null && infos.LowestBreakIteration > i)
160  break;
161 
162  state.CurrentIteration = i;
163 
164  local = body (i, state, local);
165  }
166  } finally {
167  localFinally (local);
168  }
169 
170  return new ParallelLoopResult (infos.LowestBreakIteration, !(infos.IsStopped || infos.IsExceptional));
171  }
172  #endregion For
173 
174  #region ForEach
175  static ParallelLoopResult ForEach<TSource, TLocal> (Func<int, IList<IEnumerator<TSource>>> enumerable, ParallelOptions options,
176  Func<TLocal> init, Func<TSource, ParallelLoopState, TLocal, TLocal> action,
177  Action<TLocal> destruct)
178  {
179  if (SupportsParallelism) {
180  return Parallel.ForEach (enumerable, options, init, action, destruct);
181  }
182 
183  if (enumerable == null)
184  throw new ArgumentNullException ("source");
185  if (options == null)
186  throw new ArgumentNullException ("options");
187  if (action == null)
188  throw new ArgumentNullException ("action");
189  if (init == null)
190  throw new ArgumentNullException ("init");
191  if (destruct == null)
192  throw new ArgumentNullException ("destruct");
193 
195 
196  TLocal local = init ();
197  ParallelLoopState state = new ParallelLoopState (infos);
198  CancellationToken token = options.CancellationToken;
199 
200  try {
201  var elements = enumerable (1) [0]; // 1 slice
202  while (elements.MoveNext ()) {
203  if (infos.IsStopped || infos.IsBroken.Value)
204  break;
205 
207 
208  local = action (elements.Current, state, local);
209  }
210  } finally {
211  destruct (local);
212  }
213 
214  return new ParallelLoopResult (infos.LowestBreakIteration, !(infos.IsStopped || infos.IsExceptional));
215  }
216 
224  public static ParallelLoopResult ForEach<TSource> (IEnumerable<TSource> source, Action<TSource> body)
225  {
226  if (source == null)
227  throw new ArgumentNullException ("source");
228  if (body == null)
229  throw new ArgumentNullException ("body");
230 
231  return ForEach<TSource, object> (Partitioner.Create (source),
232  ParallelOptions.Default,
233  () => null,
234  (e, s, l) => { body (e); return null; },
235  _ => { });
236  }
237 
245  public static ParallelLoopResult ForEach<TSource> (IEnumerable<TSource> source, Action<TSource, ParallelLoopState> body)
246  {
247  if (source == null)
248  throw new ArgumentNullException ("source");
249  if (body == null)
250  throw new ArgumentNullException ("body");
251 
252  return ForEach<TSource, object> (Partitioner.Create (source),
253  ParallelOptions.Default,
254  () => null,
255  (e, s, l) => { body (e, s); return null; },
256  _ => { });
257  }
258 
266  public static ParallelLoopResult ForEach<TSource> (IEnumerable<TSource> source,
267  Action<TSource, ParallelLoopState, long> body)
268  {
269  if (source == null)
270  throw new ArgumentNullException ("source");
271  if (body == null)
272  throw new ArgumentNullException ("body");
273 
274 
275  return ForEach<TSource, object> (Partitioner.Create (source),
276  ParallelOptions.Default,
277  () => null,
278  (e, s, l) => { body (e, s, -1); return null; },
279  _ => { });
280  }
281 
290  Action<TSource, ParallelLoopState> body)
291  {
292  if (body == null)
293  throw new ArgumentNullException ("body");
294 
295  return ForEach<TSource, object> (source,
296  ParallelOptions.Default,
297  () => null,
298  (e, s, l) => { body (e, s); return null; },
299  _ => { });
300  }
301 
310  Action<TSource, ParallelLoopState, long> body)
311 
312  {
313  if (body == null)
314  throw new ArgumentNullException ("body");
315 
316  return ForEach<TSource, object> (source,
317  ParallelOptions.Default,
318  () => null,
319  (e, s, i, l) => { body (e, s, i); return null; },
320  _ => { });
321  }
322 
331  Action<TSource> body)
332 
333  {
334  if (body == null)
335  throw new ArgumentNullException ("body");
336 
337  return ForEach<TSource, object> (source,
338  ParallelOptions.Default,
339  () => null,
340  (e, s, l) => { body (e); return null; },
341  _ => { });
342  }
343 
352  public static ParallelLoopResult ForEach<TSource> (IEnumerable<TSource> source,
353  ParallelOptions parallelOptions,
354  Action<TSource> body)
355  {
356  if (source == null)
357  throw new ArgumentNullException ("source");
358  if (body == null)
359  throw new ArgumentNullException ("body");
360 
361  return ForEach<TSource, object> (Partitioner.Create (source),
362  parallelOptions,
363  () => null,
364  (e, s, l) => { body (e); return null; },
365  _ => { });
366  }
367 
376  public static ParallelLoopResult ForEach<TSource> (IEnumerable<TSource> source, ParallelOptions parallelOptions,
377  Action<TSource, ParallelLoopState> body)
378  {
379  if (source == null)
380  throw new ArgumentNullException ("source");
381  if (body == null)
382  throw new ArgumentNullException ("body");
383 
384  return ForEach<TSource, object> (Partitioner.Create (source),
385  parallelOptions,
386  () => null,
387  (e, s, l) => { body (e, s); return null; },
388  _ => { });
389  }
390 
399  public static ParallelLoopResult ForEach<TSource> (IEnumerable<TSource> source, ParallelOptions parallelOptions,
400  Action<TSource, ParallelLoopState, long> body)
401  {
402  if (source == null)
403  throw new ArgumentNullException ("source");
404  if (body == null)
405  throw new ArgumentNullException ("body");
406 
407  return ForEach<TSource, object> (Partitioner.Create (source),
408  parallelOptions,
409  () => null,
410  (e, s, i, l) => { body (e, s, i); return null; },
411  _ => { });
412  }
413 
423  Action<TSource, ParallelLoopState, long> body)
424 
425  {
426  if (body == null)
427  throw new ArgumentNullException ("body");
428 
429  return ForEach<TSource, object> (source,
430  parallelOptions,
431  () => null,
432  (e, s, i, l) => { body (e, s, i); return null; },
433  _ => { });
434  }
435 
445  Action<TSource> body)
446  {
447  if (body == null)
448  throw new ArgumentNullException ("body");
449 
450  return ForEach<TSource, object> (source,
451  parallelOptions,
452  () => null,
453  (e, s, l) => { body (e); return null; },
454  _ => { });
455  }
456 
466  Action<TSource, ParallelLoopState> body)
467  {
468  return ForEach<TSource, object> (source,
469  parallelOptions,
470  () => null,
471  (e, s, l) => { body (e, s); return null; },
472  _ => { });
473  }
474 
485  public static ParallelLoopResult ForEach<TSource, TLocal> (IEnumerable<TSource> source, Func<TLocal> localInit,
486  Func<TSource, ParallelLoopState, TLocal, TLocal> body,
487  Action<TLocal> localFinally)
488  {
489  if (source == null)
490  throw new ArgumentNullException ("source");
491 
492  return ForEach<TSource, TLocal> ((Partitioner<TSource>)Partitioner.Create (source),
493  ParallelOptions.Default,
494  localInit,
495  body,
496  localFinally);
497  }
498 
509  public static ParallelLoopResult ForEach<TSource, TLocal> (IEnumerable<TSource> source, Func<TLocal> localInit,
510  Func<TSource, ParallelLoopState, long, TLocal, TLocal> body,
511  Action<TLocal> localFinally)
512  {
513  return ForEach<TSource, TLocal> (Partitioner.Create (source),
514  ParallelOptions.Default,
515  localInit,
516  body,
517  localFinally);
518  }
519 
530  public static ParallelLoopResult ForEach<TSource, TLocal> (OrderablePartitioner<TSource> source, Func<TLocal> localInit,
531  Func<TSource, ParallelLoopState, long, TLocal, TLocal> body,
532  Action<TLocal> localFinally)
533  {
534  return ForEach<TSource, TLocal> (source, ParallelOptions.Default, localInit, body, localFinally);
535  }
536 
547  public static ParallelLoopResult ForEach<TSource, TLocal> (Partitioner<TSource> source, Func<TLocal> localInit,
548  Func<TSource, ParallelLoopState, TLocal, TLocal> body,
549  Action<TLocal> localFinally)
550  {
551  return ForEach<TSource, TLocal> (source, ParallelOptions.Default, localInit, body, localFinally);
552  }
553 
565  public static ParallelLoopResult ForEach<TSource, TLocal> (IEnumerable<TSource> source, ParallelOptions parallelOptions,
566  Func<TLocal> localInit,
567  Func<TSource, ParallelLoopState, TLocal, TLocal> body,
568  Action<TLocal> localFinally)
569  {
570  if (source == null)
571  throw new ArgumentNullException ("source");
572 
573  return ForEach<TSource, TLocal> (Partitioner.Create (source), parallelOptions, localInit, body, localFinally);
574  }
575 
587  public static ParallelLoopResult ForEach<TSource, TLocal> (IEnumerable<TSource> source, ParallelOptions parallelOptions,
588  Func<TLocal> localInit,
589  Func<TSource, ParallelLoopState, long, TLocal, TLocal> body,
590  Action<TLocal> localFinally)
591  {
592  if (source == null)
593  throw new ArgumentNullException ("source");
594 
595  return ForEach<TSource, TLocal> (Partitioner.Create (source), parallelOptions, localInit, body, localFinally);
596  }
597 
609  public static ParallelLoopResult ForEach<TSource, TLocal> (Partitioner<TSource> source, ParallelOptions parallelOptions,
610  Func<TLocal> localInit,
611  Func<TSource, ParallelLoopState, TLocal, TLocal> body,
612  Action<TLocal> localFinally)
613  {
614  if (source == null)
615  throw new ArgumentNullException ("source");
616  if (body == null)
617  throw new ArgumentNullException ("body");
618 
619  return ForEach<TSource, TLocal> (source.GetPartitions, parallelOptions, localInit, body, localFinally);
620  }
621 
633  public static ParallelLoopResult ForEach<TSource, TLocal> (OrderablePartitioner<TSource> source, ParallelOptions parallelOptions,
634  Func<TLocal> localInit,
635  Func<TSource, ParallelLoopState, long, TLocal, TLocal> body,
636  Action<TLocal> localFinally)
637  {
638  if (source == null)
639  throw new ArgumentNullException ("source");
640  if (body == null)
641  throw new ArgumentNullException ("body");
642 
643  return ForEach<KeyValuePair<long, TSource>, TLocal> (source.GetOrderablePartitions,
644  parallelOptions,
645  localInit,
646  (e, s, l) => body (e.Value, s, e.Key, l),
647  localFinally);
648  }
649  #endregion ForEach
650 
651  #region Invoke
652  public static void Invoke (params Action [] actions)
657  {
658  if (actions == null)
659  throw new ArgumentNullException ("actions");
660 
661  Invoke (ParallelOptions.Default, actions);
662  }
663 
669  public static void Invoke (ParallelOptions parallelOptions, params Action [] actions)
670  {
671  if (SupportsParallelism) {
672  Parallel.Invoke (parallelOptions, actions);
673  return;
674  }
675 
676  if (parallelOptions == null)
677  throw new ArgumentNullException ("parallelOptions");
678  if (actions == null)
679  throw new ArgumentNullException ("actions");
680  if (actions.Length == 0)
681  throw new ArgumentException ("actions is empty");
682  foreach (var a in actions)
683  if (a == null)
684  throw new ArgumentException ("One action in actions is null", "actions");
685  if (actions.Length == 1) {
686  actions [0] ();
687  return;
688  }
689 
690  foreach (var action in actions) {
691  action ();
692  }
693  }
694  #endregion
695  }
696 }
697 
abstract IList< IEnumerator< KeyValuePair< long, TSource > > > GetOrderablePartitions(int partitionCount)
Opportunistically parallelize on platforms where supported.
static void Invoke(params Action [] actions)
Invoke the specified actions.
static ParallelLoopResult For(int fromInclusive, int toExclusive, Action< int > body)
Parallel for loop.
static ParallelLoopResult For(int fromInclusive, int toExclusive, Action< int > body)
Definition: Parallel.cs:97
static bool SupportsParallelism
Gets or sets whether parallelism is supported.
static ParallelLoopResult For(int fromInclusive, int toExclusive, ParallelOptions parallelOptions, Action< int > body)
Parallel for loop.
static void Invoke(params Action[] actions)
Definition: Parallel.cs:673
static ParallelLoopResult ForEach< TSource >(IEnumerable< TSource > source, Action< TSource > body)
Parallel for each loop.
static ParallelLoopResult For(int fromInclusive, int toExclusive, ParallelOptions parallelOptions, Action< int, ParallelLoopState > body)
Parallel for loop.
static ParallelLoopResult For< TLocal >(int fromInclusive, int toExclusive, Func< TLocal > localInit, Func< int, ParallelLoopState, TLocal, TLocal > body, Action< TLocal > localFinally)
Parallel for loop.
static ParallelLoopResult For(int fromInclusive, int toExclusive, Action< int, ParallelLoopState > body)
Parallel for loop.
static void Invoke(ParallelOptions parallelOptions, params Action [] actions)
Invoke the specified actions.