我有一个包含以下循环的 shell 脚本。
i=0
upperlimit=$verylargevariable
do
complexstuff RunManager file $i
i= 'expr $i +1'
done
此脚本在四核计算机上运行,根据
top
,在执行一次循环迭代时使用每个核心的大约 15%。我想将其分布在四个核心上,以便循环的每次迭代都会执行 complexstuff
四次,每个核心一次,这样资源将得到更有效的利用。我们正在讨论目前需要几个小时的计算,因此效率不仅仅是这里的良好实践。 (每次迭代的输出显然与前一次迭代无关。)
PS:主机是运行 Cent-OS 的服务器,如果有帮助的话。
使用 GNU Parallel,您可以:
seq $verylargevariable | parallel -j150% complexstuff RunManager file
150% 将为每个核心运行 1.5 个进程,因此,如果当前使用 15%,这将为您在所有 4 个核心上提供大约 100% 的性能。
要了解更多信息,请观看介绍视频:http://www.youtube.com/watch?v=OpaiGYxkSuQ
除了 Ole Tange 解决方案(看起来很棒),如果您的计算具有非常相似的持续时间,您可以尝试这样的方法:
i=0
upperlimit=$verylargevariable
do
complexstuff RunManager file $i &
i= 'expr $i + 1'
complexstuff RunManager file $i &
i= 'expr $i + 1'
complexstuff RunManager file $i &
i= 'expr $i + 1'
complexstuff RunManager file $i &
i= 'expr $i + 1'
wait
done
这样,在每次运行循环时,您将创建 4 个 bash 子进程来启动您的计算(并且由于系统很棒,它会将它们分派到不同的核心上)。如果有 4 个进程还不足以烧毁所有 cpu,请增加每个循环上创建的进程数。
快速破解解决方案:只需不断启动作业,直到达到您想要同时运行的最大作业数。毫无疑问,有比下面这个示例更清晰的细节,但这是我针对类似问题整理的内容,并且它有效。 (“睡眠”命令的持续时间可能有点过长,但我的程序每个命令都需要几分钟才能运行,因此睡眠并不会过多)
#!/bin/bash -x
PAGE="check001"
#DEBUG="-d"
DEBUG=""
ls -1 tiles/${PAGE}/line???/*.png | sort | while read f ; do
if [ -f `dirname $f`/`basename $f .png`.txt ] ; then
:
else
JOBS="`ps auxww|fgrep ../../recogniser/chocr-check|grep -v fgrep|wc -l`"
echo Before loop: JOBS = $JOBS
while [ $JOBS -ge 4 ] ; do
sleep 10
JOBS="`ps auxww|fgrep ../../recogniser/chocr-check|grep -v fgrep|wc -l`"
done
../../recogniser/chocr-check $DEBUG $f > `dirname $f`/`basename $f .png`.txt &
sleep 2
fi
done