为了最大限度地提高CPU使用率(我运行一个Debian莱尼在EC2的东西)我有一个简单的脚本来启动作业并行:
#!/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 &
...
我很满意这个工作的解决方案,但我无法弄清楚如何编写代码进一步只执行一次所有的循环已经完成。
有没有办法让这个控制?
有一个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.
使用GNU并行将会使你的脚本更短,可能更有效:
parallel 'echo "Processing "{}" ..."; do_something_important {}' ::: apache-*.log
这将运行每个CPU核心一个工作,并继续这样做,直到所有的文件进行处理。
运行前您的解决方案将基本分割作业分成组。 这32个作业4组:
GNU并行,而不是产生一个新的进程时,一个结束 - 保持CPU的活跃,从而节省了时间:
了解更多:
- 留意简要介绍介绍视频: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
- 通过教程(男子parallel_tutorial)的步行路程。 你命令行一定会喜欢你的。
我不得不近日做到这一点,结束了以下解决方案:
while true; do
wait -n || {
code="$?"
([[ $code = "127" ]] && exit 0 || exit "$code")
break
}
done;
下面是它如何工作的:
wait -n
退出尽快(可能很多)后台作业的出口之一。 它总是计算为true,循环一直持续到:
- 退出码
127
:最后一个后台作业成功退出。 在这种情况下,我们忽略退出代码,并与代码0退出子壳。 - 任何后台作业的失败。 我们只是退出子壳与退出代码。
随着set -e
,这将保证该脚本将提前终止,并通过任何失败的后台作业的退出代码。
这是我的原油的解决方案:
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
}
我们的想法是用“工作”,看看有多少孩子都在后台继续运行,等到这个数字下降(孩子退出)。 一旦发现孩子存在,接下来的工作就可以开始。
正如你所看到的,也有一些额外的逻辑来避免运行相同的实验/命令多次。 它的工作对我来说。然而,这种逻辑可能是要么跳过或进一步改进(例如,检查文件的创建时间戳,输入参数等)。