【问题标题】:Parallel.ForEach Loop with Thread-Local boolean具有线程局部布尔值的 Parallel.ForEach 循环
【发布时间】:2014-12-19 21:06:46
【问题描述】:

我已阅读 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 会将布尔值分配给每个分区,如果最后一个分区以错误结束(即匹配!=“有效的”)。 我只是担心局部变量doWork 如果在ParallelForEachLoop 方法中被多个线程访问,可能会引发异常。如果满足条件,我真的只需要设置一次doWork,即使它在整个迭代循环中只发生一次(尽管我肯定需要在每个有效匹配上运行ProcessMatch)。 我的担心有道理吗?我可以使用ParallelForEachLoop 函数而不用担心它在某些情况下可能不起作用吗?

【问题讨论】:

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


    【解决方案1】:

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

    线程局部变量使您可以执行非原子操作(可能在“期间”发生其他事情的操作,改变结果)而不必锁定资源,然后您可以不那么频繁地执行另一个操作(在最后一个块)并锁定该操作并汇总您的结果。然而,为bool 赋值是一个原子操作,因此不需要使用局部变量。在您链接到的 MSDN 示例中,他们在一个非原子整数上执行 +=,并且需要锁定或使用局部变量,就像他们在示例中所做的那样,以确保另一个线程没有将值修改为分配新结果之前+= 的左侧。

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


    1:给变量赋值是Constrained Execution Region中允许做的少数几件事之一

    【讨论】:

    • 谢谢,我猜“......为布尔值赋值是一个原子操作”是我正在寻找的(以及为变量赋值(有效)值不抛出异常)。再次感谢!
    • 大多数内置值类型都有原子赋值,我所知道的唯一一个不是在 32 位平台上运行的 long。但是你可以使用Interlocked.Read 和其他interlocked 函数来给你原子性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-01
    • 2017-09-11
    • 1970-01-01
    • 2011-08-01
    • 2018-12-13
    • 2015-11-22
    • 2015-05-24
    相关资源
    最近更新 更多