9

Is there any way to achieve the Parallel.For version of this for loop?

for (int i = 0; i < 100; i += 2) { DoStuff(i); }

I don't see an overload which accepts a step parameter, though I can't think of any reason this would be logically impossible.

The accepted answer to this and this question suggests using Parallel.ForEach on a range of ints generated using Enumerable.Range, but in my case I am using thread local data so Parallel.ForEach is not an option.

Another option is to just check if i % 2 == 0 in the body of my loop and return, but this still executes the thread local data intializer Func and finalizer Func. Below is a code snippet demonstrating this option:

Parallel.For<Bar>(0, limit, 

    () => new Bar(), //thread local data initialize

    (i, state, local) => //loop body
    {
        if (i % 2 != 0) return local;
        local.foo += DoStuff(i);
        return local;
    },

    (local) => //thread local data post-action
    {
        lock (loopLocker)
        {
            globalData.foo += local.foo;
        );
    }
);
Community
  • 1
  • 1
Rotem
  • 21,452
  • 6
  • 62
  • 109

4 Answers4

15

Here's a hint:

for (int j = 0; j < 50; j++) { i = 2*j; DoStuff(); }

In general, see if you can figure out the number of iterations and a transformation from iteration number to the variable value.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
7

Here is another way to process stepped indexes

private void ParallelForEachProcessSteppedIndexes()
        {
            Parallel.ForEach(SteppedIterator(0, 100, 2), (index) => DoStuff(index));
        }

private static IEnumerable<int> SteppedIterator(int startIndex, int endIndex, int stepSize)
        {
            for (int i = startIndex; i < endIndex; i = i + stepSize)
            {
                yield return i;
            }
        }
Toan Nguyen
  • 11,263
  • 5
  • 43
  • 59
4

Ben's suggestion is very good for constant step e.g. +2, +3 etc.

Alternatively (if your step is random) you could use Parallel.ForEach e.g.

int[] input = { 1, 3, 4, 5, 7, 10, 20, 25 }; 

Parallel.ForEach(input,
    () => new Bar(), //thread local data initialize
    (i, state, local) => //loop body
    {
        // your code
    },
    (local) => //thread local data post-action
    {
        // your code
    }

Variable i will get data from input array. You could replace input with Enumerable.Range (or combine it with With etc.)

That would work perfectly fine if you would like to get only prime number in i variable.

Tom
  • 26,212
  • 21
  • 100
  • 111
  • I don't know why I previously missed the thread local overloads of `Parallel.ForEach`, I thought thread locality was only available in `Parallel.For`. Thanks – Rotem Dec 26 '12 at 20:01
0

Toan's answer worked for me after converting to VB.NET's new Iterator function

Private Sub LoopExample()
    Parallel.ForEach(SteppedIterator(1,100,5), AddressOf Test)

End Sub

Private Iterator Function SteppedIterator(startIndex As Integer, endIndex As Integer, stepSize As Integer) As IEnumerable(Of Integer)
    For i As Integer = startIndex To endIndex Step stepSize
        Yield i
    Next

End Function

Private Sub Test(i As Integer, state As ParallelLoopState, index As Long)
    Debug.WriteLine(i.ToString)
End Sub
anachostic
  • 61
  • 1
  • 3