在 parallel.foreach 中使用局部变量

using local variables in parallel.foreach

我真的很难解决这个问题。

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

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

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

I have every iteration a stand alone one and I need not return anything from one iteration to another.

目前的问题是class正确返回的结果有时不正确。我想这是因为 processor 和 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);
        });

实际的 question/problem 已在评论中说明:

I have every iteration a stand alone one and I need not return anything from one iteration to another.

在这种情况下,您不希望 Images 是线程本地的,您只需要它们是本地的。所以解决办法就是简化:

  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();

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

        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() 访问这些结果。但是,如果多个线程 运行 并行,则第二个线程可能会在第一个线程调用它之后但在第一个线程到达 processor.getList() 之前调用 ProcessImage。这意味着第一个线程将从第二个线程获取列表结果。

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

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

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

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