parallel コマンド
forループで逐次処理させるのもいいのですが、大抵1coreしか使わない.
複数coreを使って逐次処理を複数同時に流したいときがある.
っで使うのがこの parallel コマンド.
本家様 https://www.gnu.org/software/parallel/
簡単な例として「fastq.bz2」なファイルを戻してgzファイルにしてみる
(解凍)
ls *.fastq.bz2 | parallel bzip2 -d {}
(gzip圧縮)
ls *.fastq | parallel gzip {}
計算機が持っているすべてのcoreを使ってcore分の解凍プロセスと圧縮プロセスが発生します. pigz,pixzは複数coreを同時に使っての並列処理です
ほかに簡単な例としてeman2のe2proc2dでmrcをjpegに変換してみる.
*実際には「*.mrc」とかで複数のファイルを一度に指定できるけどforを使った場合のお話
relionのMotionCorrでfload32で出力したデータを対象にしてます. fload16にeman2は未対応っぽい
for i in `find ./MotionCorr/job036 -type f -name "*_frameImage.mrc"`; do
cmd="e2proc2d.py ${i} /tmp/$(basename $i .mrc).jpeg"
echo $cmd
eval $cmd
done
findコマンドでmrcファイルを見つけて、それをforで変数iに一枚づつ入れて e2proc2d.py で jpeg で処理するって流れです.
なのでtopコマンドで見ても1つのプロセスしか表示されません
これを parallel コマンドで複数プロセスを流すようにしてみます.
「for .. done」で回すのではなく、lsとかfindで対象を集め、それを parallel コマンドに渡します
一度に実行できる数は「-j」で指定できますが、何も指定しないとそのマシンのcore数となります
[saber@rockylinux relion40_tutorial_precalculated_results]$ find ./MotionCorr/job036 -type f -name "*_frameImage.mrc"
./MotionCorr/job036/Movies/20170629_00021_frameImage.mrc
./MotionCorr/job036/Movies/20170629_00022_frameImage.mrc
./MotionCorr/job036/Movies/20170629_00023_frameImage.mrc
./MotionCorr/job036/Movies/20170629_00024_frameImage.mrc
./MotionCorr/job036/Movies/20170629_00025_frameImage.mrc
./MotionCorr/job036/Movies/20170629_00026_frameImage.mrc
./MotionCorr/job036/Movies/20170629_00027_frameImage.mrc
./MotionCorr/job036/Movies/20170629_00028_frameImage.mrc
./MotionCorr/job036/Movies/20170629_00029_frameImage.mrc
./MotionCorr/job036/Movies/20170629_00030_frameImage.mrc
./MotionCorr/job036/Movies/20170629_00031_frameImage.mrc
./MotionCorr/job036/Movies/20170629_00035_frameImage.mrc
./MotionCorr/job036/Movies/20170629_00036_frameImage.mrc
./MotionCorr/job036/Movies/20170629_00037_frameImage.mrc
./MotionCorr/job036/Movies/20170629_00039_frameImage.mrc
./MotionCorr/job036/Movies/20170629_00040_frameImage.mrc
./MotionCorr/job036/Movies/20170629_00042_frameImage.mrc
./MotionCorr/job036/Movies/20170629_00043_frameImage.mrc
./MotionCorr/job036/Movies/20170629_00044_frameImage.mrc
./MotionCorr/job036/Movies/20170629_00045_frameImage.mrc
./MotionCorr/job036/Movies/20170629_00046_frameImage.mrc
./MotionCorr/job036/Movies/20170629_00047_frameImage.mrc
./MotionCorr/job036/Movies/20170629_00048_frameImage.mrc
./MotionCorr/job036/Movies/20170629_00049_frameImage.mrc
(これを)
[saber@rockylinux relion40_tutorial_precalculated_results]$ find ./MotionCorr/job036 -type f -name "*_frameImage.mrc" | parallel -j 4 e2proc2d.py {} /tmp/{/}
(テストを行うには「--dry-run」を加える
[saber@rockylinux relion40_tutorial_precalculated_results]$ find ./MotionCorr/job036 -type f -name "*_frameImage.mrc" | parallel -j 4 --dry-run e2proc2d.py {} /tmp/{/}
で行ける
この際のtopは
となって4プロセスが同時に働いている.
findコマンドの後のパイプ(|)で見つかったPATH名そのものをsed/awk/perlやらで修正してparallelコマンドに繋げるものあり.
find ./MotionCorr/job036 -type f -name "*_frameImage.mrc" | \
awk -F "/" '{print $0,$3,$5}' | \
parallel -j 4 --colsep ' ' --dry-run e2proc2d.py {1} /tmp/{2}__{3}
1 images, processing 0-0 stepping by 1
1 images
1 images, processing 0-0 stepping by 1
1 images
:
:
(「--colsep」で区切り文字を定義します)
find ./MotionCorr/job036 -type f -name "*_frameImage.mrc" | parallel --colsep '/' echo {2} {5}
MotionCorr 20170629_00021_frameImage.mrc
MotionCorr 20170629_00022_frameImage.mrc
:
:
1プロセスごとにGPUIDを変更したいなら、「-j」と「{%}」を駆使します. 「{#}」は連番となります
find ./MotionCorr/job036 -type f -name "*_frameImage.mrc" | parallel -j 4 --colsep '/' echo '$(({%} - 1))' {5} {#}
0 20170629_00021_frameImage.mrc 1
1 20170629_00022_frameImage.mrc 2
2 20170629_00023_frameImage.mrc 3
3 20170629_00024_frameImage.mrc 4
0 20170629_00025_frameImage.mrc 5
1 20170629_00026_frameImage.mrc 6
2 20170629_00027_frameImage.mrc 7
3 20170629_00028_frameImage.mrc 8
0 20170629_00029_frameImage.mrc 9
:
:
あと例としてGautomatchでGPU分のジョブを発行する方法とか Gautomatch/bash
bashの変数の文字列操作と似てますが
値 | プレイスホルダ | 変換値 |
/data/projectA/raw/20230516/A00001.mrc | {} | /data/projectA/raw/20230516/A00001.mrc |
{.} | /data/projectA/raw/20230516/A00001 | |
{/} | A00001.mrc | |
{/.} | A00001 | |
{//} | /data/projectA/raw/20230516 | |
bash | ||
mrc=/data/projectA/raw/20230516/A00001.mrc | ${mrc} | /data/projectA/raw/20230516/A00001.mrc |
${mrc#/} | data/projectA/raw/20230516/A00001.mrc | |
${mrc##*/} | A00001.mrc | |
${mrc#*.} | mrc | |
${mrc%.*} | /data/projectA/raw/20230516/A00001 | |
${mrc%%.mrc} | /data/projectA/raw/20230516/A00001 | |
${mrc%/*} | /data/projectA/raw/20230516 | |
${mrc/data\/projectA\/raw\/} | /20230516/A00001.mrc | |
${mrc/data\/projectA\/raw\//tmp/} | /tmp/20230516/A00001.mrc | |
$(basename $mrc .mrc) | A00001 | |
$(basename $mrc .mrc).jpeg | A00001.jpeg |
ctffindは改行コードで区別して引数を充てている
こんな感じで.
/public/EM/ctffind/ctffind.exe --amplitude-spectrum-input > CtfFind/job003/Movies/20170629_00024_frameImage_PS_ctffind4.log << EOF
CtfFind/job003/Movies/20170629_00024_frameImage_PS.mrc
CtfFind/job003/Movies/20170629_00024_frameImage_PS.ctf
1.39955
200
1.4
0.1
512
30
5
5000
50000
500
no
no
yes
100
no
no
EOF
exit 0
これをparallelで回すならこんな感じかな.
ctfファイルを /tmp に置いてますけど適時変更よろ.
「echo -e」で埋め込んだ改行コード(\n)を展開させてそれをpipeで繋いでctffindに渡してます
find ./Micrographs/ -name *.mrc | \
parallel -j 4 'echo -e "{}\n/tmp/{/.}.ctf\n1.39955\n200\n1.4\n0.1\n512\n30\n5\n5000\n50000\n500\nno\nno\nyes\n100\nno\nno\n"|/apps/ctffind-4.1.14/ctffind'