使用 Bash 并行运行任务

使用 Bash 并行运行任务

我正在使用这个脚本来分析数据。

#!/bin/bash
inlist=/aut/cl/tera/mja/scripts
in=/aut/cl/tera/mja/data/ran_ready/
out=/aut/cl/tera/mja/data/mas/aft/
for i in $(cat $inlist/list.txt); do
echo "$i" 
mri_binarize --i ${in}/${i}/mri/aseg.mgz --o ${out}/${i}/masks/cc.nii.gz --match 41 42 43 44 45 
flirt -in ${out}/${i}/masks/cc.nii.gz -ref ${out}/${i}/T1.nii -out ${out}/${i}/masks/cc2T1.nii.gz -omat ${out}/${i}/masks/cc2T1.mat -bins 256 -cost corratio -searchrx -90 90 -searchry -90 90 -searchrz -90 90 -dof 12  -interp trilinear

echo "$i ... done"    
wait
done

该脚本在 list.txt 中提到的条目列表(50 个条目)上运行两个命令行。对于每个条目,该脚本需要半小时才能完成工作。我想使用以下命令同时对 list.txt 中的所有条目运行此脚本“xargs”或任何其他可能的方式!

我们如何修改这个脚本以使其更加高效?

答案1

如果你有 GNU Parallel,你可以这样做:

doit() {
  i=$1
  echo "$i" 
  mri_binarize --i ${in}/${i}/mri/aseg.mgz --o ${out}/${i}/masks/cc.nii.gz --match 41 42 43 44 45 
  flirt -in ${out}/${i}/masks/cc.nii.gz -ref ${out}/${i}/T1.nii -out ${out}/${i}/masks/cc2T1.nii.gz -omat ${out}/${i}/masks/cc2T1.mat -bins 256 -cost corratio -searchrx -90 90 -searchry -90 90 -searchrz -90 90 -dof 12  -interp trilinear
  echo "$i ... done"
}
export -f doit

parallel doit :::: $inlist/list.txt

这将为每个核心运行 1 个作业。

所有新计算机都具有多个内核,但大多数程序本质上是串行的,因此不会使用多个内核。然而,许多任务是极其可并行化的:

  • 在许多文件上运行相同的程序
  • 对文件中的每一行运行相同的程序
  • 为文件中的每个块运行相同的程序

GNU Parallel 是一个通用并行器,可以轻松地在同一台计算机或多台您可以通过 ssh 访问的计算机上并行运行作业。

如果您想要在 4 个 CPU 上运行 32 个不同的作业,则并行化的直接方法是在每个 CPU 上运行 8 个作业:

简单的调度

相反,GNU Parallel 在完成后会生成一个新进程 - 保持 CPU 处于活动状态,从而节省时间:

GNU 并行调度

安装

如果您的发行版未打包 GNU Parallel,您可以进行个人安装,不需要 root 访问权限。这样做可以在 10 秒内完成:

(wget -O - pi.dk/3 || curl pi.dk/3/ || fetch -o - http://pi.dk/3) | bash

对于其他安装选项,请参阅http://git.savannah.gnu.org/cgit/parallel.git/tree/README

了解更多

查看更多示例:http://www.gnu.org/software/parallel/man.html

观看介绍视频:https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

浏览本教程:http://www.gnu.org/software/parallel/parallel_tutorial.html

注册电子邮件列表以获得支持:https://lists.gnu.org/mailman/listinfo/parallel

答案2

如果程序并行运行没有任何问题,为什么不简单地将它们发送到后台:

for i in $(cat $inlist/list.txt); do    
    echo "$i" 
    ( 
        mri_binarize --i ${in}/${i}/mri/aseg.mgz --o ${out}/${i}/masks/cc.nii.gz --match 41 42 43 44 45 
        flirt -in ${out}/${i}/masks/cc.nii.gz -ref ${out}/${i}/T1.nii -out ${out}/${i}/masks/cc2T1.nii.gz -omat ${out}/${i}/masks/cc2T1.mat -bins 256 -cost corratio -searchrx -90 90 -searchry -90 90 -searchrz -90 90 -dof 12  -interp trilinear
        echo "$i ... done"        
    ) &
done

括号将命令组合在一起并在子 shell 中运行它们,因此我们可以将命令一起发送到后台。我假设该flirt命令需要在mri_binarize.如果没有,只需&在两个命令后添加一个:

mri_binarize --i ${in}/${i}/mri/aseg.mgz --o ${out}/${i}/masks/cc.nii.gz --match 41 42 43 44 45 &
flirt -in ${out}/${i}/masks/cc.nii.gz -ref ${out}/${i}/T1.nii -out ${out}/${i}/masks/cc2T1.nii.gz -omat ${out}/${i}/masks/cc2T1.mat -bins 256 -cost corratio -searchrx -90 90 -searchry -90 90 -searchrz -90 90 -dof 12  -interp trilinear &

相关内容