GNU Parallel はシェルスクリプトの並列処理を簡単に実現できるツール。
一番シンプルな使い方は、標準入力でコマンドを受け取り、それを並列で実行するというもの。
この方法は Pythonを使ったスクリプト生成 と相性が良い。

以下のようなオプションをよく使うのでコピペ&振り返りがしやすいようにまとめておく

cat tasks.txt | parallel --jobs 40% --bar --joblog joblog.tsv --result result --timeout 30m
  • tasks.txt のそれぞれの行に実行したいシェルスクリプトを記入しておく
  • --bar はプログレスバーで進捗を表示
    • --bar--eta の強化版。--eta--progress の強化版。とりあえず --bar を使っておけばいい
      • ただし、--bar--eta を使うと、コマンドが全部でいくつであるかを先に知る必要が出るため、すべてのコマンドを受け取り終わってからでないとコマンドの実行が始まらない。
    • parallel でコマンドを実行する際、出力はコマンド全体が終わるまで画面に書き出されないのだが、--lb を指定するとコマンドの出力を随時画面に書き出す。--bar とは相性が悪いが、結果を常に確認したいときに使うとよい
  • --jobs で CPU 使用率を指定する代わりに -j 4 のようにすると並列処理数を直接指定できる
  • --halt now,fail=1 とすると 1 つでもジョブが失敗したらその時点で止める
  • --joblog joblog.tsv でコマンド実行履歴をファイルに保存しておける。更に以下のオプションを付けることで、この実行履歴を再実行に使うことができる
    • --resumeまだ実行していなかったタスクを再実行できる
    • --retry-failed失敗したタスク(エラーコードが非ゼロのタスク)だけをもう一度実行できる
    • --resume-failed失敗したタスクとまだ実行していなかったタスクを両方再実行できる
    • 実行済みタスクか否かの判定は joblog.tsv に保存される 実行スクリプト(コマンドと引数)のみを見て判定しているので、スクリプトの中身を書き換えても再実行されないことに注意、逆に実行スクリプトが違ったら実質的に同じコマンドでも再実行してしまうことに注意
  • --results result
    • コマンド・標準出力・標準エラー出力がこのディレクトリ内にそれぞれ保存される
  • --timeout 30m
    • 30 分でジョブを強制終了する。固まったジョブが CPU・キューを占有し続けるのを防ぐのに使える。一つのジョブがあまりに長時間かかっている場合、何か問題があって詰まっている場合が多い。 result に書き出されている出力などを確認して原因を修正してから --retry-failed で再実行するとよい

pueue との併用

pueue は rust で書かれている並列ジョブ管理ソフト。

parallel と比べた特徴として

  • 機能がシンプル
  • pueue で出てくるジョブリストが見やすい
  • pueue add/remove/log/--group XXX など使い方が直感的
  • 失敗したジョブをもう一度実行などの高度な機能は(自分が知らないだけかもしれないが)なさそう
  • これでジョブを 1000 個とか実行するとログが長すぎて見にくそう

という印象。なので parallel で管理するほどではない少量のジョブや、parallel コマンド自体をキューに並べておきたいときに使うと良さそう
pueue の README にも 同じことが書いてあった