xargs: потеря вывода при перенаправлении stdout в файл в параллельном режиме

Я использую GNU xargs (версия 4.2.2) в параллельном режиме и, похоже, надежно теряю вывод при перенаправлении в файл. При перенаправлении на канал он работает правильно.

Следующие команды оболочки демонстрируют минимальный, полный и поддающийся проверке пример проблемы. Я генерирую 2550 чисел, используя xargs, чтобы разбить их на строки по 100 аргументов, каждая из которых составляет 26 строк, где 26-я строка содержит только 50 аргументов.

# generate numbers 1 to 2550 where each number is on its own line
$ seq 1 2550 > /tmp/nums
$ wc -l /tmp/nums
2550 /tmp/nums

# piping to wc is accurate: 26 lines, 2550 args
$ xargs -P20 -n 100 </tmp/nums | wc
     26    2550   11643

# redirecting to a file is clearly inaccurate: 22 lines, 2150 args
$ xargs -P20 -n 100 </tmp/nums >/tmp/out; wc /tmp/out
     22  2150 10043 /tmp/out

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

Редактировать:

Появляется при использовании >> (создать/добавить в файл) в оболочке, проблема не проявляется:

# appending to file
$ >/tmp/out
$ xargs -P20 -n 100 </tmp/nums >>/tmp/out; wc /tmp/out
     26    2550   11643

# creating and appending to file
$ rm /tmp/out
$ xargs -P20 -n 100 </tmp/nums >>/tmp/out; wc /tmp/out
     26    2550   11643

person snap    schedule 08.09.2015    source источник
comment
Я получаю точный вывод в обоих случаях. Shell> wc -l /tmp/nums 2550 /tmp/nums Shell> xargs -P20 -n 100 </tmp/nums | wc 26 2550 11643 Shell> xargs -P20 -n 100 </tmp/nums >/tmp/out; wc /tmp/out 26 2550 11643 /tmp/out Shell>   -  person Sriharsha Kalluru    schedule 08.09.2015
comment
Надежно ли вы получите правильный результат, если очистите выходной файл, а затем используете перенаправление >> вместо >? Если да, то этому есть какое-то объяснение.   -  person Jonathan Leffler    schedule 08.09.2015
comment
@JonathanLeffler: Похоже, ты прав. С >> проблема не проявляется. Я попытался создать файл заранее и перенаправить с помощью и использовать «›» (обрезая существующий файл), и проблема, кажется, появляется снова.   -  person snap    schedule 08.09.2015
comment
Когда вы используете перенаправление >, какие числа появляются в начале /tmp/out? Это числа вроде 1, 2, 3 или числа вроде 2001, 2002, 2003? У меня возникли некоторые проблемы с поиском правдоподобного механизма проблемы. Поведение канала и добавления достаточно легко объяснить. Но поведение с > должно быть практически таким же, и мне остается только гадать, как что-то ломается. У вас есть в наличии truss или strace? Если это так, то было бы поучительно посмотреть, что делает процесс xargs (но не — по крайней мере, в первую очередь — что делают его потомки). […продолжение…]   -  person Jonathan Leffler    schedule 08.09.2015
comment
[…продолжение…] Есть ли в xargs.log какая-либо полезная информация после запуска strace -o xargs.log xargs -P 20 -n 100 </tmp/nums > /tmp/out? Я думаю о чем-то вроде lseek() в файловом дескрипторе 1, но я не уверен, насколько это правдоподобно. Одной из проблем может быть то, что на самом деле это ребенок причиняет вред; в этом случае вам нужно будет использовать опцию «следить за детьми» (-f), чтобы увидеть, что вызывает проблемы. Но вывод будет намного объемнее. Я получаю «правильный» вывод как в Mac OS X 10.10.5, так и в Ubuntu 14.04 LTS (работает на виртуальной машине под Mac OS X).   -  person Jonathan Leffler    schedule 08.09.2015
comment
Спасибо за предложение использовать strace. Сейчас анализирую вывод. Проблема возникает в Ubuntu 14.04 LTS (также на виртуальной машине), но я заметил, что в некоторых системах она более заметна, чем в других. Я обнаружил, что проблема быстро возникает в грубом цикле while: seq 1 2550 > /tmp/nums; while true; do xargs -P20 -n 100 </tmp/nums >/tmp/out; wc /tmp/out; done | grep -v ' 26 '. Я попробовал это на OSX 10.10.4 и не смог проявить эту проблему. [1/2]   -  person snap    schedule 08.09.2015
comment
Я хотел бы прочитать больше вопросов, как ваш!   -  person wap26    schedule 08.09.2015


Ответы (2)


Ваша проблема связана с тем, что выходные данные разных процессов смешиваются. Здесь показано:

parallel perl -e '\$a=\"1{}\"x10000000\;print\ \$a,\"\\n\"' '>' {} ::: a b c d e f
ls -l a b c d e f
parallel -kP4 -n1 grep 1 > out.par ::: a b c d e f
echo a b c d e f | xargs -P4 -n1 grep 1 > out.xargs-unbuf
echo a b c d e f | xargs -P4 -n1 grep --line-buffered 1 > out.xargs-linebuf
echo a b c d e f | xargs -n1 grep 1 > out.xargs-serial
ls -l out*
md5sum out*

Решение состоит в буферизации вывода каждого задания либо в памяти, либо во временных файлах (как это делает GNU Parallel).

person Ole Tange    schedule 08.09.2015
comment
Я согласен с тем, что нет абсолютно никакого контроля над микшированием вывода на stdout (если только write() дочернего процесса не ограничены по размеру, атомарны, и приложение разрешает микширование вывода), но это не объясняет проигрыш ввод, который происходит как в моем примере, так и в вашем. Я фактически переключился на параллельный из-за группировки вывода. - person snap; 09.09.2015
comment
Это связано с тем, что для одного и того же файла открыто несколько файловых дескрипторов: если они пишутся друг за другом, проблем нет. Если они пишут одновременно, они будут писать в одни и те же позиции в файле. Это также объясняет, почему вы не видите проблемы, если вы перенаправляете на канал вместо файла: в канале нет позиции файла. Это также объясняет, почему ›› не приводит к такому поведению. - person Ole Tange; 09.09.2015

Я знаю, что этот вопрос касается xargs, но если у вас по-прежнему возникают проблемы с ним, то, возможно, GNU Parallel может помочь. Ваш вызов xargs будет переведен на:

$ < /tmp/nums parallel -j20 -N100 echo > /tmp/out; wc /tmp/out
26  2550 11643 /tmp/out
person Jeroen Janssens    schedule 08.09.2015