У меня есть задача, которая обрабатывает список файлов на стандартный ввод. Время запуска программы является значительным, и количество времени, которое занимает каждый файл, варьируется в широких пределах. Я хочу порождать значительное количество этих процессов, а затем отправлять работу тем, кто не занят. Есть несколько различных инструментов командной строки, которые почти делают то, что я хочу, я сузил это до двух почти работающих вариантов:
find . -type f | split -n r/24 -u --filter="myjob"
find . -type f | parallel --pipe -u -l 1 myjob
Проблема заключается в том, что split
выполняется чистый циклический перебор, поэтому один из процессов отстает и остается позади, задерживая завершение всей операции; while parallel
хочет порождать один процесс на N строк или байтов ввода, и я трачу слишком много времени на издержки запуска.
Есть ли что-то подобное, что будет повторно использовать процессы и линии подачи для тех процессов, которые имеют разблокированные stdins?
источник
split
команда? Имя конфликтует со стандартной утилитой обработки текста.myjob
готов получить больше информации. Нет никакого способа узнать, что программа готова обрабатывать больше входных данных, все, что вы можете знать, это то, что некоторый буфер где-то (буфер канала, буфер stdio) готов получить больше ввода. Можете ли вы сделать так, чтобы ваша программа отправила какой-то запрос (например, отобразить подсказку), когда она будет готова?read
вызовы, сделает свое дело. Это довольно большое программирование.-l 1
вparallel
args? IIRC, который указывает параллельно обрабатывать одну строку ввода на задание (то есть одно имя файла на разветвление myjob, поэтому много накладных расходов при запуске).Ответы:
Это не выглядит возможным в таком общем случае. Это означает, что у вас есть буфер для каждого процесса, и вы можете наблюдать за буферами извне, чтобы решить, куда поместить следующую запись (планирование) ... Конечно, вы можете написать что-то (или использовать пакетную систему, такую как slurm)
Но в зависимости от процесса вы можете предварительно обработать ввод. Например, если вы хотите загружать файлы, обновлять записи из БД или тому подобное, но 50% из них в конечном итоге будут пропущены (и поэтому у вас большая разница в обработке в зависимости от ввода), тогда просто установите препроцессор он проверяет, какие записи займут много времени (файл существует, данные были изменены и т. д.), поэтому все, что поступит с другой стороны, гарантированно займет достаточно равное количество времени. Даже если эвристика не идеальна, вы можете получить значительное улучшение. Вы можете записать остальные в файл и обработать их впоследствии таким же образом.
Но это зависит от вашего варианта использования.
источник
Нет, нет общего решения. Ваш диспетчер должен знать, когда каждая программа готова прочитать другую строку, и я не знаю ни одного стандарта, который бы позволял это делать. Все, что вы можете сделать, это поставить строку на STDOUT и ждать, пока что-то ее поглотит; на самом деле не существует хорошего способа для производителя на конвейере сказать, готов ли следующий потребитель или нет.
источник
Я так не думаю. В моем любимом журнале была однажды статья о программировании на Bash, которая делала то, что вы хотите. Я готов верить, что если бы были инструменты для этого, они бы упомянули их. Итак, вы хотите что-то вроде:
Очевидно, вы можете изменить вызов на действующий рабочий скрипт по своему вкусу. Журнал, о котором я упоминаю, изначально занимается такими вещами, как настройка каналов и запуск рабочих потоков. Проверьте
mkfifo
это, но этот маршрут намного сложнее, поскольку рабочие процессы должны сигнализировать ведущему процессу, что они готовы получать больше данных. Таким образом, вам нужно одно fifo для каждого рабочего процесса, чтобы отправить ему данные, и одно fifo для главного процесса, чтобы получать данные от рабочих.ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ Я написал этот сценарий из головы. У него могут быть некоторые проблемы с синтаксисом.
источник
find . -type f | while read i
, чемfor i in $(find . -type f)
.Для GNU Parallel вы можете установить размер блока, используя --block. Однако для этого требуется, чтобы у вас было достаточно памяти для хранения 1 блока в памяти для каждого из запущенных процессов.
Я понимаю, что это не совсем то, что вы ищете, но сейчас это может быть приемлемым решением.
Если ваши задачи в среднем занимают одно и то же время, вы можете использовать mbuffer:
источник
Попробуй это:
mkfifo
для каждого процесса.Затем повесьте
tail -f | myjob
каждый пятерку.Например, настройка рабочих (процессы myjob)
В зависимости от вашего приложения (myjob) вы можете использовать задание -s для поиска остановленных заданий. В противном случае перечислите процессы, отсортированные по процессору, и выберите тот, который потребляет наименьшее количество ресурсов. Имеется отчет о работе, например, путем установки флага в файловой системе, когда он хочет больше работы.
Предполагая, что работа останавливается при ожидании ввода, используйте
jobs -sl
например, узнать pid остановленной работы и назначить ей работуЯ проверил это с
Я должен признать, что это было просто придумано.
источник
Что действительно нужно для решения этой проблемы, так это механизм очередей некоторого типа.
Возможно ли, чтобы задания считывали свой ввод из очереди, такой как очередь сообщений SYSV, и затем, чтобы программы, запущенные параллельно, просто помещали значения в очередь?
Другая возможность - использовать каталоги для очереди, например так:
pending
mv
первый файл, который он видит в каталоге, в одноуровневый каталог сpending
именемinprogress
.pending
источник
подробно излагая ответ @ ash, вы можете использовать очередь сообщений SYSV для распределения работы. Если вы не хотите писать свою собственную программу на C, есть утилита,
ipcmd
которая может помочь. Вот что я поставил вместе , чтобы передать выходfind $DIRECTORY -type f
на$PARALLEL
число процессов:Вот тестовый прогон:
источник
Если вы не можете оценить, как долго будет обрабатываться конкретный входной файл, и у рабочих процессов нет возможности отчитываться перед планировщиком (как они это делают в обычных сценариях параллельных вычислений - часто через MPI ), вам, как правило, не повезло - либо платите штраф за то, что некоторые работники обрабатывают ввод дольше, чем другие (из-за неравенства ввода), или платите штраф за создание одного нового процесса для каждого входного файла.
источник
GNU Parallel изменилась за последние 7 лет. Итак, сегодня он может это сделать:
Этот пример показывает, что процессам 11 и 10 дается больше блоков, чем процессам 4 и 5, потому что 4 и 5 читаются медленнее:
источник