Распараллеливание цикла while с массивами, считанными из файла в bash

у меня есть цикл while в Bash обрабатывается следующим образом:

while IFS=$'t' read -r -a line;
do
    myprogram ${line[0]} ${line[1]} ${line[0]}_vs_${line[1]}.result;
done < fileinput

Он читает из файла с этой структурой, для справки:

foo   bar
baz   foobar

и так далее (с разделителями табуляции).

Я хотел бы распараллелить этот цикл (так как записей много, и обработка может быть медленной), используя GNU parallel, однако примеры не ясны о том, как я бы назначил каждую строку массиву, как я делаю здесь.

каким было бы возможное решение (альтернативы GNU параллельная работа)?

3 ответов


от https://www.gnu.org/software/parallel/man.html#EXAMPLE:-Use-a-table-as-input:

"""
Содержимое table_file.tsv:

foo<TAB>bar
baz <TAB> quux

запуск:

cmd -o bar -i foo
cmd -o quux -i baz

вы можете работать:

parallel -a table_file.tsv --colsep '\t' cmd -o {2} -i {1}

"""

так что в вашем случае это будет:

cat fileinput | parallel --colsep '\t' myprogram {1} {2} {1}_vs_{2}.result

parallel здесь не обязательно; просто запустите все процессы в фоновом режиме, а затем дождитесь их завершения. Массив также не нужен, так как вы можете дать read более одной переменной для заполнения:

while IFS=$'\t' read -r f1 f2;
do
    myprogram "$f1" "$f2" "${f1}_vs_${f2}.result" &
done < fileinput
wait

это запускает одно задание для пункт в вашем списке, тогда как parallel можно ограничить количество заданий, выполняемых одновременно. Вы можете сделать то же самое в bash, но это сложно.


Я хотел бы @chepner hack. И, кажется, не так сложно выполнить подобное поведение с ограничением количества параллельных выполнений:

while IFS=$'\t' read -r f1 f2;
do
    myprogram "$f1" "$f2" "${f1}_vs_${f2}.result" &

    # At most as number of CPU cores
    [ $( jobs | wc -l ) -ge $( nproc ) ] && wait
done < fileinput

wait

это ограничивает выполнение при максимальном количестве ядер процессора, присутствующих в системе. Вы можете легко изменить это, заменив $( nproc ) на желаемую сумму.

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