使用步长不等于1的Parallel.For

9

有没有办法实现这个 for 循环的 Parallel.For 版本?

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

我没有看到接受步长参数的重载版本,但我想不出任何逻辑上不可能的原因。
这个这个问题的被接受答案中建议使用Enumerable.Range生成的int范围上的Parallel.ForEach,但在我的情况下,我正在使用线程本地数据,所以Parallel.ForEach不是一个选项
另一个选择是在循环体中检查i % 2 == 0return,但这仍然会执行线程本地数据初始化器Func和终结器Func。以下是演示此选项的代码片段:
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;
        );
    }
);
4个回答

14
这是一个提示:
for (int j = 0; j < 50; j++) { i = 2*j; DoStuff(); }

一般来说,看看你能否找出迭代次数和迭代次数与变量值之间的转换关系。

2
没有什么比一个非常简单的解决方案让我感到更愚蠢了 :) - Rotem

8
这里有另一种处理分步索引的方法。
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;
            }
        }

4

Ben的建议非常适用于常量步长,例如+2、+3等。

如果您的步长是随机的,您可以使用Parallel.ForEach

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
    }

变量i将从input数组中获取数据。您可以将input替换为Enumerable.Range(或与With等组合)。

如果您只想在i变量中获取质数,则这将完美地起作用。


我不知道为什么之前错过了 Parallel.ForEach 的线程本地重载,我以为线程本地性只在 Parallel.For 中可用。谢谢。 - Rotem

-1

在转换为VB.NET的新迭代器函数后,Toan的答案对我起作用了。

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接