Parallel.For结合ConcurrentBag使用疑似非线程安全问题咨询
你遇到的「ConcurrentBag疑似收到其他线程数据」的问题和ConcurrentBag本身无关,该集合是标准线程安全实现,你的代码存在多处语法、逻辑错误,具体问题如下:
问题排查
- 语法错误
- if判断语句多写了一个冗余左括号,没有对应右括号闭合,代码无法正常编译
- 条件判断中访问xSource数组未指定索引
i,直接对整个数组和double类型做减法运算,属于类型错误,得到的计算结果完全不符合预期,导致大量不符合条件的数值被添加到集合中,这是你误以为拿到其他线程数据的核心原因,正确写法应为访问xSource[i]
- 方法调用错误
如果你用到的Mat.Abs是EmguCV等第三方库提供的矩阵处理方法,传入两个double的差值作为参数,要么会直接编译报错,要么会产生非预期的计算结果,导致判断条件完全失效,建议替换为System.Math.Abs处理double类型的绝对值计算。 - 性能优化建议
海量数据处理场景下,每次迭代都调用线程安全集合的Add方法会产生大量锁开销,推荐使用Parallel.For的本地线程状态重载,每个线程先操作本地普通List,所有迭代完成后再合并结果,既可以避免锁竞争,性能也远高于直接操作ConcurrentBag。
修正后代码示例
public static void GetNearXvalues(double deltaX, double xCenter, double[] xSource, out double[] xNear) { var globalResult = new List<double>(); // 使用带本地状态的Parallel.For重载降低锁开销 Parallel.For<List<double>>( 0, xSource.Length, // 每个工作线程初始化本地存储容器 () => new List<double>(), // 单迭代处理逻辑,仅操作本地List无锁开销 (i, state, localList) => { if (Math.Abs(xCenter - xSource[i]) < deltaX) { localList.Add(xSource[i]); } return localList; }, // 线程结束后合并本地结果到全局容器,仅此处需要加锁 localList => { lock (globalResult) { globalResult.AddRange(localList); } } ); xNear = globalResult.ToArray(); }
内容的提问来源于stack exchange,提问作者Wolfgang
相关产品推荐
相关产品推荐

