GNU Parallel: немедленно отображать stderr/stdout заданий поочередно в порядке выполнения заданий

Вопрос или проблема

Я знаю, что GNU Parallel буферизует std/stderr, потому что не хочет, чтобы результаты выполнения заданий были перепутаны. Но если я запускаю свои задачи с помощью parallel do_something ::: task_1 task_2 task_3, есть ли способ, чтобы вывод task_1 отображался немедленно, а затем, после завершения task_1, вывод task_2 до его текущего состояния и так далее.

Если Parallel не может решить эту проблему, есть ли какая-нибудь другая аналогичная программа, которая смогла бы?

С версии 20160422 программы parallel вы можете получать полные строки вывода как можно быстрее с помощью --line-buffer.

Добавив --keep-order, программа будет выдавать строки только от самой старой выполняемой задачи – другими словами, строки от разных задач не будут путаться.

Пример:

parallel --keep-order --line-buffer do_something ::: task_1 task_2 task_3

Смотрите страницу man и доступные короткие опции:

       --line-buffer
       --lb
           Буферизовать вывод по строкам.

           --group сохранит вывод вместе для целой задачи. --ungroup позволит вывести смешанный вывод, где половина строки поступает от одной задачи, а другая половина - от другой задачи. --line-buffer занимает промежуточное положение между этими двумя: GNU parallel
           будет выводить полную строку, но позволит смешивать строки разных задач.

           --line-buffer требует больше вычислительных ресурсов, чем --group и --ungroup, но может быть намного быстрее, чем --group, если процессор не является ограничивающим фактором.

           Обычно --line-buffer не буферизует на диске и может обрабатывать неограниченное количество данных, но будет буферизовать на диске, когда комбинируется с: --keep-order, --results, --compress и --files. Это сделает его таким же медленным, как --group, и ограничит вывод доступным дисковым пространством.

           С помощью --keep-order --line-buffer будет выводить строки из первой задачи непрерывно во время ее выполнения, затем строки из второй задачи, пока она выполняется. Он будет буферизовать полные строки, но задачи не будут смешиваться. Сравните:

             parallel -j0 'echo {};sleep {};echo {}' ::: 1 3 2 4
             parallel -j0 --lb 'echo {};sleep {};echo {}' ::: 1 3 2 4
             parallel -j0 -k --lb 'echo {};sleep {};echo {}' ::: 1 3 2 4

           См. также: --group --ungroup --keep-order --tag

parallel на самом деле не делает резервирования на вывод в порядке. Просто бывает, что задачи обычно достаточно маленькие и равномерно распределены по времени СPU, чтобы выходить в порядке. Вы это замечаете больше, когда у вас много работающих задач, или когда продолжительность их выполнения сильно различается.

По умолчанию parallel будет запускать только то количество задач, сколько имеют ядер ваш процессор. На большинстве ноутбуков и настольных компьютеров это 2-4, что означает, что одновременно выполняется всего пара задач. Вы можете увеличить это с помощью -j.

Вот пример, который демонстрирует, что порядок выполнения задач не соответствует порядку их подачи.

seq 20 | parallel -j 20 'sleep $[RANDOM % 20]; echo '

Вывод в моей системе был (у вас он, вероятно, будет другим):

7
3
13
20
8
16
2
4
18
17
1
5
9
14
12
6
10
19
11
15

seq 20 – это команда, которая выводит числа от 1 до 20. Я передаю это в parallel и затем указываю ему запустить 20 одновременно выполняемых задач, чтобы убедиться, что они все начнут одновременно. 'sleep $[\[RANDOM][1] % 20]; использует команду sleep, плюс параметр zsh, который вернет случайное число от 1 до 20. Каждая задача будет спать это случайное время, а затем echo. Как только задача выполнит echo, вы сразу получите вывод от parallel.

Вы также можете сделать что-то подобное с parallel --shuf, который перемешает порядок задач.

Ответ или решение

Для решения вашей задачи с использованием GNU Parallel и с целью немедленного отображения вывода стандартного потока (stdout) и потока ошибок (stderr) по одному за раз в порядке выполнения задач, вы можете воспользоваться опциями, доступными начиная с версии 20160422.

  1. Опции --line-buffer и --keep-order: Сначала добавьте опцию --line-buffer, чтобы получить строки вывода немедленно, как только они будут доступны. Это позволит избежать буферизации вывода, что гарантирует, что вы получите целые строки, не дожидаясь завершения всех задач. Использование опции --keep-order позволит выводить строки в том порядке, в котором задачи были запущены, что сохранит последовательность вывода.

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

parallel --keep-order --line-buffer do_something ::: task_1 task_2 task_3

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

  1. Описание опций:

    • --line-buffer: Эта опция позволяет GNU Parallel выводить данные построчно, что обеспечивает более быстрый доступ к улучшенному выводу, чем с использованием стандартной буферизации.
    • --keep-order: Эта опция гарантирует, что вывод будет упорядочен, т.е. данные от первых завершенных задач будут показаны первыми, сохраняя порядок выполнения.
  2. Примечания:

    • Следует учитывать, что использование --line-buffer потребует больше ресурсов процессора, чем стандартный режим работы, но это может значительно ускорить вывод, когда процессор не является узким местом.
    • Также имейте в виду, что при использовании опций, таких как --results или --compress, может происходить дополнительное буферизование на диске, ограничивая скорость вывода.
  3. Альтернативные решения: Если вы столкнулись с ограничениями GNU Parallel, вы можете рассмотреть использование других инструментов, которые позволяют управлять выводом параллельных задач, таких как xargs, GNU Screen или tmux, но они могут потребовать дополнительной настройки для достижения аналогичного поведения.

С помощью описанных выше настроек вы сможете эффективно управлять выводом ваших заданий, получая результат сразу после завершения каждой задачи.

Оцените материал
Добавить комментарий

Капча загружается...