Parallel.ForEach循环使用Thread-Local布尔值

时间:2014-12-19 21:06:47

标签: c# .net thread-safety parallel.foreach

我已阅读Microsoft关于运行Parallel.ForEach loop with thread-local variables的指南,这对于计数器和/或更新对象有意义。我的问题是在处理本地布尔变量时需要它。 请考虑以下代码(它只是一个示例,实际代码执行的更多):

public bool ParallelForEachLoopWithThreadLocalBoolVariable(IEnumerable<string> items)
{
    bool doWork = false;
    Parallel.ForEach<string, bool>(items,
                                   () => false,
                                   (match, loop, madeChange) =>
                                   {
                                        if (match == "valid")
                                        {
                                            madeChange = true;
                                            ProcessMatch(match);
                                        }   
                                        return madeChange;
                                   },
                                   (changed) => doWork = changed
                                   );
    return doWork;
}

public bool ParallelForEachLoop(IEnumerable<string> items)
{
    bool doWork = false;
    Parallel.ForEach(items, match =>
                     {
                        if (match == "valid")
                        {
                            doWork = true;
                            ProcessMatch(match);
                        }   
                    });
    return doWork;
}

我的最终目标是在ProcessMatch()方法中传播完成的工作,并返回一个标记,指示整体工作是否有所不同。 我倾向于使用ParallelForEachLoop方法,因为我相信ParallelForEachLoopWithThreadLocalBoolVariable会将布尔值分配给每个分区,如果最后一个分区执行工作结束为false,则最终会得到错误的解释(即匹配!=&#34;有效&#34;)。 我担心局部变量doWork如果被ParallelForEachLoop方法中的多个线程访问,可能会抛出异常。我真的只需要在条件满足时设置doWork一次,即使它只在整个迭代循环中发生一次(我肯定需要在每个有效匹配上运行ProcessMatch)。 我的恐惧是否合理?我是否可以使用ParallelForEachLoop函数而不担心它在某些情况下可能无效?

1 个答案:

答案 0 :(得分:1)

首先,为变量指定一个有效值(注意,一个变量 NOT 一个属性)你永远不会抛出 1 的异常,所以你关注的是第二种方法无效。

线程局部变量是这样你可以执行非原子操作(可能有其他事情发生的操作&#34;在#34;它,改变结果)而不必锁定资源,然后你可以执行另一个操作频率较低(在最后一个块中)并锁定该操作并汇总结果。但是,为bool赋值是一个原子操作,因此不需要使用局部变量。在MSDN示例中,您链接到它们对非整数的整数执行+=并且需要锁定或使用局部变量,就像在示例中一样,以确保另一个线程没有修改在分配新结果之前,+=左侧的值。

简而言之,请使用您的第二个版本。


1:为变量赋值是您在Constrained Execution Region

中可以做的少数事情之一