Bash: 在多个核心上运行同一程序

15

我可以访问一台机器,其中有10个核心的访问权限--我想实际使用它们。在我的机器上,我习惯这样做:

for f in *.fa; do
  myProgram (options) "./$f" "./$f.tmp"
done

我有10个文件需要进行操作,我们称它们为blah00.fa,blah01.fa,...,blah09.fa。

采用这种方法的问题是,myProgram一次只能使用一个内核,如果在多核机器上像这样运行10次,那么我将一次只能使用1个内核,不能充分利用我的机器。

我该如何更改脚本,以便同时运行所有10个.fa文件?我查看了在多个核心上运行循环处理的bash方法,但我无法完全按照我想要的方式使用该命令。


2
你试过使用“gnu parallel”吗?有什么问题没有解决吗? - Fredrik Pihl
1
你尝试过在那个答案中使用GNU Parallel建议吗? - Dave S.
4
seq 0 10 | parallel myProgram -opt1 -opt2 ./blah{}.fa ./blah{}.tmp - Jonathan Dursi
4
您不需要root权限来安装它,只需下载源代码并运行命令 ./configure --prefix=${HOME}; make; make install 就可以将其安装到您的主目录中。 - Jonathan Dursi
向机器的系统管理员展示了这个,说服他在机器上安装并行处理——感谢您的建议! - Joe
显示剩余3条评论
3个回答

12

您可以使用

for f in *.fa; do
    myProgram (options) "./$f" "./$f.tmp" &
done
wait

它将同时启动所有工作,然后等待它们全部完成后再继续。如果您的工作数量超过核心数,您将启动所有工作,并让操作系统调度程序负责进程交换。

一种修改方法是每次启动10个工作。

count=0
for f in *.fa; do
    myProgram (options) "./$f" "./$f.tmp" &
    (( count ++ ))        
    if (( count = 10 )); then
        wait
        count=0
    fi
done

但是与使用parallel相比,这种方式效率较低,因为你不能在旧任务完成之前启动新的任务,也无法检测到在你成功启动10个作业之前是否已经完成了旧作业。wait允许您等待单个特定进程或所有后台进程,但不会告诉您任意一组后台进程中的任何一个何时完成。


2
Bash的下一个版本将有一个选项(wait -n)。目前,您可以像这样做一些事情,但由于一些错误,它有点危险,这些错误也将在下一个版本中修复。 - ormaaj

8

使用GNU Parallel,您可以执行以下操作:

parallel myProgram (options) {} {.}.tmp ::: *.fa

来源:http://git.savannah.gnu.org/cgit/parallel.git/tree/README

= 全部安装 =

GNU Parallel的完整安装非常简单:

./configure && make && make install

如果您不是root用户,可以将~/bin添加到您的路径中,并在~/bin和~/share中安装:

./configure --prefix=$HOME && make && make install

如果你的系统缺少'make'程序,你可以将src/parallel、src/sem、src/niceload和src/sql复制到环境变量中的某个目录下。

= 最小安装 =

如果你只需要使用parallel,并且没有安装'make'程序(可能是因为系统较旧或者使用了Microsoft Windows):

wget http://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel
chmod 755 parallel
cp parallel sem
mv parallel sem dir-in-your-$PATH/bin/

观看介绍视频以了解更多信息:https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1


0
# Wait while instance count less than $3, run additional instance and exit
function runParallel () {
    cmd=$1
    args=$2
    number=$3
    currNumber="1024"
    while true ; do
        currNumber=`ps -e | grep -v "grep" | grep " $1$" | wc -l`
        if [ $currNumber -lt $number ] ; then
            break
        fi
        sleep 1
    done
    echo "run: $cmd $args"
    $cmd $args &
}

loop=0
# We will run 12 sleep commands for 10 seconds each 
# and only five of them will work simultaneously
while [ $loop -ne 12 ] ; do
    runParallel "sleep" 10 5
    loop=`expr $loop + 1`
done

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接