在parallel.foreach中使用局部变量

时间:2015-04-17 20:37:25

标签: c# .net multithreading parallel-processing parallel.foreach

我很难解决这个问题。

代码应该从文件对话框中导入图像。并且应该处理每个图像并将其发送到正确的类。 处理器是一个检测形状的类,所以基本上我发送每个图像并检测其中的形状(在类处理器中过滤到某个标准)

newList将获得图像中所有形状的中心。

我对Parallelism知之甚少,而我似乎无法想出如何解决这个问题。 请记住,我不需要将任何内容从一次迭代传递到另一次迭代。我只想一次处理和修正图像,整个操作分为线程。

  

我每次迭代都是独立的,我不需要从一次迭代返回到另一次迭代。

目前问题是从类正确返回的结果有时是不正确的。我想这是因为处理器和newList也必须是本地的?如果是,我该如何解决这个问题?如果不是我哪里出错了?

另请注意,使用普通的foreach可以正常使用

这是我的代码:

Parallel.ForEach(ofd.FileNames,
        (file) =>
        {
            Image exam = Image.FromFile(file);
            var cvImage = new Image<Bgr, byte>((Bitmap)exam);
            processor = processorMain;
            processor.ProcessImage(cvImage);
            List<Point> newList = new List<Point>();
            newList = processor.getList();
            correct.correct(cvImage, answerKey, nOptions);
        });

2 个答案:

答案 0 :(得分:2)

实际问题/问题在评论中说明:

  

我每次迭代都是独立的,我不需要从一次迭代返回到另一次迭代。

在这种情况下,您不希望您的Image是本地线程,您只需要本地。所以解决方案是简化:

  Parallel.ForEach(ofd.FileNames,
    (file) =>
    {
        var cvImage = new Image<Bgr, byte>((Bitmap)exam);
        processor = processorMain;
        processor.ProcessImage(cvImage);
        List<Point> newList = new List<Point>();
        newList = processor.getList();
        correct.correct(newList, cvImage, answerKey, nOptions);
    });

但是你的代码并没有在任何地方使用file,所以这只是一个粗略的猜测。它还不正确。

另一方面,processorMainanswerKeynOptions的使用是潜在的问题。


经过多次评论后,您需要的是:

IList<Image> result = ofd.FileNames
       .AsParallel()
       .Select( (file) => 
{
    Image exam = Image.FromFile(file);
    ...
    return exam;
}).ToList();

答案 1 :(得分:0)

您的问题可能出在以下几行代码中:

        processor = processorMain;
        processor.ProcessImage(cvImage);
        List<Point> newList = processor.getList(); // don't make a new list and then just throw it away by overwriting it.

看起来processor正在处理您的图片并存储一些您稍后通过processor.getList()调用访问的结果。但是如果多个线程并行运行,第二个线程可能会在第一个线程调用它之后但在第一个线程到达ProcessImage之前调用processor.getList()。这意味着第一个线程将从第二个线程获得列表结果。

最简单的解决方案是在每次迭代中创建一个处理器:

        processor = new MyProcessorType();
        processor.ProcessImage(cvImage);
        List<Point> newList = new List<Point>();
        newList = processor.getList();

这取决于处理器不依赖任何静态数据的假设。

另一种选择是修改处理器,使点列表存储在线程本地存储中。