Какой простой механизм для синхронных пулированных процессов Unix? - PullRequest
4 голосов
/ 28 февраля 2012

Мне нужно ограничить количество процессов, выполняемых параллельно. Например, я хотел бы выполнить эту команду psuedo:

export POOL_PARALLELISM=4
for i in `seq 100` ; do
    pool foo -bar &
done

pool foo -bar # would not complete until the first 100 finished.

Таким образом, несмотря на то, что 101 foo s поставлены в очередь на запуск, только 4 будут работать в любой момент времени. pool выполнит fork () / exit () и поставит в очередь остальные процессы до завершения.

Есть ли простой механизм, чтобы сделать это с помощью инструментов Unix? at и batch не применяются, потому что они обычно вызываются на вершине минуты, а также выполняют задания последовательно. Использование очереди не обязательно является лучшим, потому что я хочу, чтобы они были синхронными.

Прежде чем написать оболочку C, использующую семафоры и разделяемую память, а затем отладить взаимоблокировки, которые я обязательно введу, кто-нибудь может порекомендовать bash / shell или другой инструментальный механизм для достижения этой цели.

1 Ответ

4 голосов
/ 28 февраля 2012

Определенно нет необходимости писать этот инструмент самостоятельно, есть несколько хороших вариантов.

make

make может сделать это довольно легко, но для управления процессом он все же полагается на файлов . (Если вы хотите выполнить какую-либо операцию для каждого входного файла, который создает выходной файл, это может быть удивительным.) Параметр командной строки -j будет запускать указанное количество задач, а параметр командной строки -l средняя загрузка будет укажите среднюю загрузку системы, которую необходимо выполнить перед началом новых задач. (Это может быть хорошо, если вы хотите выполнить некоторую работу «в фоновом режиме». Не забудьте о команде nice(1), которая также может помочь здесь.)

Итак, быстрый (и непроверенный) Makefile для конвертации изображений:

ALL=$(patsubst cimg%.jpg,thumb_cimg%.jpg,$(wildcard *.jpg))

.PHONY: all

all: $(ALL)
        convert $< -resize 100x100 $@

Если вы запустите это с make, оно будет запускаться по одному. Если вы запускаете с make -j8, он запустит восемь отдельных заданий. Если вы запустите make -j, он запустится сотнями. (При компиляции исходного кода я считаю, что удвоение числа ядер является отличной отправной точкой. Это дает каждому процессору что-то делать во время ожидания запросов дискового ввода-вывода. Разные машины и разные нагрузки могут работать по-разному.)

xargs

xargs предоставляет параметр командной строки --max-procs. Это лучше всего, если параллельные процессы можно разделить на основе одного входного потока с помощью либо отдельных входных команд ascii NUL, либо разделенных входных команд новой строки. (Ну, опция -d позволяет вам выбрать что-то еще, но эти два являются общими и простыми.) Это дает вам преимущество использования мощного синтаксиса выбора файлов find(1) вместо написания смешных выражений, таких как Makefile пример выше, или позволяет ваш ввод полностью не связаны с файлы . (Подумайте, есть ли у вас программа для деления больших составных чисел на простые множители - вписать эту задачу в make будет в лучшем случае неудобно. xargs может сделать это легко.)

Предыдущий пример может выглядеть примерно так:

find . -name '*jpg' -print0 | xargs -0 --max-procs 16 -I {} convert {} --resize 100x100 thumb_{}

parallel

Пакет moreutils (доступен по крайней мере в Ubuntu) предоставляет команду parallel. Он может выполняться двумя различными способами: либо выполнять указанную команду с разными аргументами, либо параллельно выполнять разные команды. Предыдущий пример может выглядеть так:

parallel -i -j 16 convert {} -resize 100x100 thumb_{} -- *.jpg

beanstalkd

Программа beanstalkd использует совершенно другой подход: она предоставляет шину сообщений для отправки запросов и серверы заданий блок для заданий после ввода выполните задания, а затем вернитесь к ожиданию нового задания в очереди. Если вы хотите записать данные обратно в конкретный HTTP-запрос, который инициировал задание, это может быть не очень удобно, поскольку вы должны сами предоставить этот механизм (возможно, другую «трубу» на сервере beanstalkd), но если Конечным результатом является отправка данных в базу данных, или по электронной почте, или что-то похожее асинхронное, это может быть проще всего интегрировать в существующее приложение.

...