Преобразование цикла for в Task.Parallel.For

У меня есть процедура bool IsExistImage(int i) . задача процедуры обнаружить изображение и вернуть логическое значение независимо от того, существует оно или нет.

у меня есть PDF-файл из более чем 100 страниц, который я разделяю и отправляю только имя файла с помощью метода. имена файлов на самом деле являются номером страницы основного файла 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, это всегда правильно.

Я не понимаю, в чем здесь проблема. что я должен применить здесь. Есть ли какая-то техника, которую я упускаю?


person Abdur Rahim    schedule 16.12.2013    source источник
comment
Что делает метод isExistImage? Вы должны использовать List<int> вместо ArrayList.   -  person Johnbot    schedule 16.12.2013
comment
Как сказал @Johnbot, используйте общую коллекцию. Кроме того, какой тип коллекции pdf?   -  person Allan Elder    schedule 16.12.2013
comment
Я использовал. но никакого результата. Pdf — это еще один массив файлов, содержащий такие имена файлов, как 1,2,3,4,....,25,...   -  person Abdur Rahim    schedule 16.12.2013


Ответы (2)


Ваша проблема в том, что ArrayList (и большинство других коллекций .Net) не является потокобезопасным.

Есть несколько способов исправить это, но я думаю, что в данном случае лучший вариант — использовать PLINQ:

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

Это будет использовать несколько потоков для вызова (странно названного) метода isExistImage, что именно то, что вам нужно, а затем вернуть List<int>, содержащий индексы, соответствующие условию.

Возвращаемый список не будет отсортирован. Если хотите, добавьте AsOrdered() перед Where().

Кстати, вам действительно не следует использовать ArrayList. Если вам нужен список целых чисел, используйте List<int>.

person svick    schedule 16.12.2013
comment
Я пробовал общий List‹int›. Но никакого положительного результата. isExistImage() возвращает логическое значение. не инт. почему имя странное? - person Abdur Rahim; 17.12.2013
comment
Простое переключение с ArrayList на List<int> не поможет, потому что List<int> также не является потокобезопасным. Я понимаю, что он возвращает логическое значение, поэтому я предложил вам использовать PLINQ Where, вы пробовали это? И имя странное, потому что оно грамматически неправильное. - person svick; 17.12.2013
comment
Позже я понимаю, что ты действительно понял. Затем я реализовал PLINQ, как вы предложили. Тестирование продолжается. В одном случае это сработало. Я подтвержу это. Я не уверен в грамматической неправильности. Пожалуйста, объясни. - person Abdur Rahim; 17.12.2013

  1. ArrayList не является потокобезопасным; просмотрите параллельные коллекции здесь.

  2. Является ли isExistImage потокобезопасным? т.е. вы блокируете перед обновлением каких-либо переменных-членов ??

person Allan Elder    schedule 16.12.2013
comment
извините за пометку минус. это была ошибка. вы можете отредактировать ответ, тогда я могу проголосовать за это. - person Abdur Rahim; 16.12.2013