将for循环转换为Task.Parallel.For

时间:2013-12-16 13:56:17

标签: c# parallel-processing task-parallel-library parallel-for

我有一个程序 bool IsExistImage(int i)。检测图像并返回bool的过程的任务是否存在。

我有一个100多页的PDF,我拆分并通过该方法只发送文件名。文件名实际上是主PDF文件的页面编号。像1,2,3,...,125,..

检测到图像后,我的方法正确保存了页面列表。为此,我使用了这段代码:

ArrayList array1 = new ArrayList();
for(int i=1;i<pdf.length;i++)
{
   if(isExistImage(i))
   {
       array1.add(i);
   }
}

此过程运行时间超过1小时(显然对于isExistImage()方法中的内部工作。)。我可以向你保证,方法范围之外没有任何对象/变量是全局的。

因此,为了缩短时间,我使用了Task.Parallel For循环。这就是我所做的:

System.Threading.Tasks,Parallel.For(1,pdf.Length,i =>
{
    if(isExistImage(i))
        array1.Add(i);
}

但这不能正常运作。有时图像检测是正确的。但大多数时候它错了。当我使用非并行for循环时,它总是正确的。

我不明白这里的问题是什么。我应该在这里申请什么我缺少什么技术吗?

2 个答案:

答案 0 :(得分:3)

您的问题是ArrayList(以及大多数其他.Net集合)不是线程安全的。

有几种方法可以解决这个问题,但我认为在这种情况下,最好的选择是使用PLINQ:

List<int> pagesWithImages = ParallelEnumerable.Range(1, pdf.Length)
    .Where(i => isExistImage(i))
    .ToList();

这将使用多个线程来调用(奇怪命名的)isExistImage方法,这正是您想要的,然后返回包含与条件匹配的索引的List<int>

不会对返回的列表进行排序。如果需要,请在AsOrdered()之前添加Where()

顺便说一下,你真的不应该使用ArrayList。如果需要整数列表,请使用List<int>

答案 1 :(得分:0)

  1. ArrayList不是线程安全的;查看并发集合here

  2. 是isExistImage线程安全吗?即你在更新任何成员变量之前锁定了吗?