最大化CPU使用率(我在EC2中的Debian Lenny上运行)我有一个简单的脚本来并行启动作业:
#!/bin/bash
for i in apache-200901*.log; do echo "Processing $i ..."; do_something_important; done &
for i in apache-200902*.log; do echo "Processing $i ..."; do_something_important; done &
for i in apache-200903*.log; do echo "Processing $i ..."; do_something_important; done &
for i in apache-200904*.log; do echo "Processing $i ..."; do_something_important; done &
...
我对这个有效的解决方案非常满意,但是我无法弄清楚如何编写进一步的代码,只有在所有循环完成后才会执行。
有没有办法控制这个?
答案 0 :(得分:76)
有一个bash
内置命令。
wait [n ...]
Wait for each specified process and return its termination sta‐
tus. Each n may be a process ID or a job specification; if a
job spec is given, all processes in that job’s pipeline are
waited for. If n is not given, all currently active child pro‐
cesses are waited for, and the return status is zero. If n
specifies a non-existent process or job, the return status is
127. Otherwise, the return status is the exit status of the
last process or job waited for.
答案 1 :(得分:25)
使用GNU Parallel将使您的脚本更短,可能更高效:
parallel 'echo "Processing "{}" ..."; do_something_important {}' ::: apache-*.log
这将为每个CPU核心运行一个作业,并继续执行此操作,直到处理完所有文件。
您的解决方案基本上会在运行前将作业拆分为多个组。这里有4组32个职位:
GNU Parallel会在完成后生成一个新进程 - 保持CPU处于活动状态,从而节省时间:
了解更多信息:
答案 2 :(得分:3)
我最近必须这样做并最终得到以下解决方案:
while true; do
wait -n || {
code="$?"
([[ $code = "127" ]] && exit 0 || exit "$code")
break
}
done;
以下是它的工作原理:
只要其中一个(可能很多)后台作业退出, wait -n
就会退出。它总是计算为true,循环继续,直到:
127
:成功退出最后一个后台作业。在
在这种情况下,我们忽略退出代码并使用代码退出子shell
0 使用set -e
,这将保证脚本提前终止并通过任何失败的后台作业的退出代码。
答案 3 :(得分:0)
这是我的原始解决方案:
function run_task {
cmd=$1
output=$2
concurency=$3
if [ -f ${output}.done ]; then
# experiment already run
echo "Command already run: $cmd. Found output $output"
return
fi
count=`jobs -p | wc -l`
echo "New active task #$count: $cmd > $output"
$cmd > $output && touch $output.done &
stop=$(($count >= $concurency))
while [ $stop -eq 1 ]; do
echo "Waiting for $count worker threads..."
sleep 1
count=`jobs -p | wc -l`
stop=$(($count > $concurency))
done
}
这个想法是使用" jobs"看看有多少孩子在后台活动并等到这个数字下降(一个孩子退出)。一旦孩子存在,就可以开始下一个任务。
正如您所看到的,还有一些额外的逻辑可以避免多次运行相同的实验/命令。它为我完成了工作。但是,可以跳过或进一步改进此逻辑(例如,检查文件创建时间戳,输入参数等)。