Параллельная GNU не делит работу равномерно
Насколько я понимаю, опция -X должна равномерно распределять аргументы между заданиями. Тем не менее, я получаю очень искаженный дистрибутив:
user@host:/tmp/ptest$ count() {
> echo $#
> }
user@host:/tmp/ptest$ export -f count
user@host:/tmp/ptest$ count *.jpg
5825
user@host:/tmp/ptest$ parallel -X count ::: *.jpg
5039
197
197
197
195
Интересно, что использование только подмножества файлов приводит к равномерному распределению параметров:
user@host:/tmp/ptest$ count p129*.jpg
975
user@host:/tmp/ptest$ parallel -X count ::: p129*.jpg
244
244
244
243
user@host:/tmp/ptest$ count p12*.jpg
4007
user@host:/tmp/ptest$ parallel -X count ::: p12*.jpg
1002
1002
1002
1001
user@host:/tmp/ptest$ count p13*.jpg
1818
user@host:/tmp/ptest$ parallel -X count ::: p13*.jpg
455
455
455
453
Почему неправильно в первом случае и как я могу это исправить?
1 ответ
-X
распределяет равномерно, когда он поражает EOF.
Так что в вашем случае он заполняет буфер для полной командной строки (5039 имен) и запускает ее. Затем он читает еще 800 имен, пока не достигнет EOF. Этого недостаточно, чтобы начать полную работу, поэтому они распределяются между рабочими местами.
Смотрите страницу 37 https://zenodo.org/record/1146014
Это сделано таким образом, чтобы избежать необходимости читать все задания заранее, так как все задания могут быть недоступны (подумайте tail -f file.names | parallel ...
).
Возможно, будет лучше, если GNU Parallel прочитает достаточно имен, чтобы заполнить все рабочие места, прежде чем начинать следующую работу в -X
режим, чтобы он мог обнаружить EOF раньше. Это, однако, не было реализовано. Патч приветствуется.
Обходной путь должен использовать:
ls *.jpg |
parallel --round --pipe -N1 parallel -Xj1 count
Он не может выводить после каждого задания, но может выполнять вывод с буферизацией:
ls *.jpg |
parallel --lb --round --pipe -N1 parallel --lb -Xj1 count
Если имена файлов содержат \n:
printf '%s\0' *.jpg |
parallel --recend '\0' --round --lb --pipe -N1 parallel -0Xj1 count