Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //#define ORDER
- //-----------------------------------------------------------------------------
- using System;
- using System.Collections;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- using System.Linq;
- using System.Threading;
- using System.Threading.Tasks;
- namespace ConsoleApp1
- {
- static class Program
- {
- static void Main()
- {
- var arr = new int[21];
- int arrayLength = arr.Length;
- var myPartitioner = new MyPartitioner(arrayLength);
- Console.WriteLine("Parallel.ForEach");
- Parallel.ForEach(
- myPartitioner,
- range => Console.WriteLine(range)
- );
- Console.WriteLine();
- Console.WriteLine("PLinq");
- myPartitioner
- .AsParallel()
- #if ORDER
- .OrderBy(a => a.Start)
- .ToList()
- .ForEach(a => Console.WriteLine(a));
- #else
- .ForAll(a => Console.WriteLine(a));
- #endif
- }
- }
- //-------------------------------------------------------------------------
- internal class MyPartitioner : OrderablePartitioner<(int Start, int End)>
- {
- private int _arrayLength;
- //---------------------------------------------------------------------
- public MyPartitioner(int arrayLength)
- : base(true, true, true)
- => _arrayLength = arrayLength;
- //---------------------------------------------------------------------
- public override bool SupportsDynamicPartitions => true;
- //---------------------------------------------------------------------
- // For Parallel.ForEach this method is not needed, only for PLinq
- public override IList<IEnumerator<KeyValuePair<long, (int Start, int End)>>> GetOrderablePartitions(int partitionCount)
- {
- var dynamicPartitions = this.GetOrderableDynamicPartitions();
- var partitions = new IEnumerator<KeyValuePair<long, (int Start, int End)>>[partitionCount];
- for (int i = 0; i < partitions.Length; ++i)
- partitions[i] = dynamicPartitions.GetEnumerator();
- return partitions;
- }
- //---------------------------------------------------------------------
- public override IEnumerable<KeyValuePair<long, (int Start, int End)>> GetOrderableDynamicPartitions()
- => new ArrayRangePartitions(_arrayLength);
- //---------------------------------------------------------------------
- // Could be implemented as enumerator in GetOrderableDynamicPartitions
- // and with the fields of the class.
- // But then only one "iteration" Parallel.ForEach or PLinq can be done.
- // With the separate class multiple iterations can be done.
- private class ArrayRangePartitions : IEnumerable<KeyValuePair<long, (int Start, int End)>>
- {
- private readonly int _arrayLen;
- private readonly int _chunkSize;
- private readonly int _noOfChunks;
- private int _chunkIdx;
- //-----------------------------------------------------------------
- public ArrayRangePartitions(int arrayLen)
- {
- int chunkSize = arrayLen / Environment.ProcessorCount;
- _noOfChunks = arrayLen / chunkSize;
- _arrayLen = arrayLen;
- _chunkSize = chunkSize;
- }
- //-----------------------------------------------------------------
- IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
- //-----------------------------------------------------------------
- public IEnumerator<KeyValuePair<long, (int Start, int End)>> GetEnumerator()
- {
- while (true)
- {
- int chunkIdx = Interlocked.Increment(ref _chunkIdx) - 1;
- if (chunkIdx > _noOfChunks) yield break;
- if (chunkIdx < _noOfChunks)
- {
- int start = chunkIdx * _chunkSize;
- int end = start + _chunkSize;
- yield return new KeyValuePair<long, (int Start, int End)>(chunkIdx, (start, end));
- }
- else
- {
- int start = chunkIdx * _chunkSize;
- int end = _arrayLen;
- yield return new KeyValuePair<long, (int Start, int End)>(chunkIdx, (start, end));
- }
- }
- }
- }
- }
- }
Add Comment
Please, Sign In to add comment