1

В настоящее время у меня очень большой каталог, содержащий более 9000 папок, каждый из которых содержит jpeg-изображения (в среднем 40 на каждую папку).Параллелизация программ обработки изображений на большом наборе изображений

Моя программа принимает входную папку с изображениями и выводит вектор характеристик изображений в этой папке в текстовые файлы:

./process_image images/ output/ 

У меня также есть скрипт, с использованием в качестве следующего:

./script.sh dirlist.txt images/ output/ 1 

Первый вход dirlist.txt содержит имена папок внутри каталога ввода Второй и третий входы являются базовым каталогом для входов и выходов. 4-ый аргумент является индексом, для которого запись в DirList Я хочу, чтобы получить доступ к

Приведенный выше пример будет вызывать, если предположить, что imageset1 был с индексом 1 в dirlist.txt:

./process_image images/imageset1/ output/imageset1/ 

Если бы я сделайте это последовательно, мне понадобится несколько дней, чтобы обработать все 9000 папок. Каков наилучший метод распараллеливания в этом случае? Должен ли я писать сценарий, который разделяет 9000 папок на блоки и запускает сценарий отдельно, каждый из которых работает с определенным диапазоном индексов? Кроме того, как определить, сколько программ я могу запустить, учитывая, что один исполняемый файл может варьироваться от 100 МБ до 1 ГБ в ОЗУ? У меня 32 ГБ оперативной памяти.

+0

Что является узким местом? io или процессор или пропускную способность памяти? Что C++ связано с этой проблемой? – Yakk

+0

Я не уверен, как подойти к проблеме и каково мое узкое место. Программа написана на C++. – Olivier

+0

Я просто пробовал обрабатывать 10 папок одновременно, а использование моего процессора - около 90%. Можно ли сказать, что моим узким местом является процессор? Я работаю на i7-3770 – Olivier

ответ

5

Я регулярно обрабатывать 65,000+ изображений в день, и я просто о всегда используйте GNU Parallel - см. here и here. Я бы не стал разбираться с C-кодом!

Он позволяет указать, сколько заданий должно выполняться параллельно или просто использовать по умолчанию одно задание для ядра процессора. Он довольно прост в использовании.Все, что вам сделать, это изменить ваш script.sh так, что вместо того, чтобы начать рабочие места, он просто повторяет все команды он начал бы, по одному в каждой строке, в stdout, а затем по конвейеру, что в parallel, как это

script.sh | parallel 

Вы можете добавить флаги, например -j 8, для запуска 8 заданий параллельно или -k, чтобы сохранить порядок вывода, если это необходимо.

script.sh | parallel -j 8 -k 

Аналогично, если вы беспокоитесь об использовании памяти, вы можете сказать parallel только начать новые рабочие места, когда система имеет по крайней мере 1 Гб свободной памяти:

script.sh | parallel --memfree 1G 

Вы также можете добавить список других машин, и она будет распределять работу через них для вас :-)

Вот маленький пример:

#!/bin/bash 
# script.sh 

for i in {0..99}; do 
    echo "echo Start job $i; sleep 5; echo End job $i" 
done 

Тогда

script.sh | parallel 

и 500 секунд работы будет сделано в 70 секунд на моем 8-машине ядра, или 21 секунд, если я использую parallel -j 25.

+0

«-noswap», как известно, hrmmm .... неоптимальный. Вместо этого попробуйте новый '--memfree 1G'. –

+0

@OleTange Спасибо, как обычно, за бесценные данные. –

+0

Спасибо за сообщение. Очень полезный материал. К сожалению, сейчас я нахожусь в Windows, и не смог получить работу GNU Parallel. Я думаю, что я нашел альтернативы. Знаете ли вы, что синтаксис выполняется так же, как «script.sh | parallel -j 8» с помощью xargs? – Olivier

0
  1. узкого

    • использования процессора не является допустимым узким знак
    • лучшим способом решить, что является узким местом является измерениями
    • , когда вы попали в узком месте, то использование процессора обычно ударил 100% или около
    • , но это означает только то, что достигнуто какое-то узкое место
    • если узкое место м IO, тогда использование ЦП может быть низким ...
    • для измерения CPU/MEM вам нужно использовать другой процессор и скорость передачи данных
    • так изменить настройки в BIOS, чтобы увидеть, если раз быстро изменить
    • это не всегда помогает определить источник в этом случае
    • вам должны измерять время выполнения частей программы и посмотреть, что происходит медленно
    • затем определить его самостоятельно на основе того, что делает, что часть кода
    • есть также инструменты профилирования, которые там делают некоторые из этого автоматически
  2. распараллеливание

    • можно распараллелить только Потокобезопасные части кода
    • поэтому если вы используете не-Потокобезопасную LIBS тогда эти части не могут быть параллелизовать
    • также, если у вас есть зависимые части коды друг другу, то распараллеливание не слишком набирает
    • , не зная больше о фоновой обработке вашей задачи, трудно сказать
    • настолько простым и безопасным способом является папка процесса на поток
  3. число нитей

    • Я обычно использовать столько потоков, сколько у меня процессора доступны
    • это число может быть получен (на окнах) от сродства системы
    • от времени требуют приложений, которые я использую 1-й ЦП в качестве основного кода и только остальные в качестве потоков
    • в вашем случае с использованием слишком большого количества потоков приведет к конфликту с IO-образами (если у вас нет RAM/SSD-привода)
  4. планирования

    • для аналогичной продолжительности задачи просто разделить задачи на резьбу равномерно
    • для самых разных задач автономной работы использовать какое-то планирование
    • , например, создать Que задач
    • и затем periodicaly проверить все темы, если они заняты
    • найти первую бесплатную задачу и задачу выборки из que to it
    • не забудьте добавить Sleep() в этом цикле
    • , если все задачи выполняются, то остановить все потоки и выйти
+1

'Sleep'? Ты наверное шутишь. Для простаивающего потока намного легче подобрать работу. Это мгновенно, и устраняет необходимость в основном цикле, который почти всегда спит и обычно наполовину сон, когда что-то нужно сделать. – MSalters

+0

@MSalters (+1) Я согласен, что самоиспользование потоков выполняется быстрее, но требуется гораздо больше опыта, чтобы написать их правильно (в потокобезопасном режиме) для более длительных заданий, таких как несколько секунд в папке и основной петле. Сон вокруг графического планирования ОС - это отходы, которые не являются (но это необходимо измерять при конкретной реализации). – Spektre

+0

Безопасность потоков, если это довольно тривиально: просто поместите мьютексы в список открытых задач. Чтение и обработка одного изображения достаточно сложны, чтобы мьютекс не вызывал значительных разногласий. (Если contention _is_ проблема, разбейте список задач в N подсписок, защищенных N мьютексами) – MSalters