可以说我在Bash中有一个循环:
for foo in `some-command`
do
do-something $foo
done
Run Code Online (Sandbox Code Playgroud)
do-something是cpu绑定,我有一个漂亮闪亮的4核处理器.我希望能够一次跑到4 do-something岁.
天真的做法似乎是:
for foo in `some-command`
do
do-something $foo &
done
Run Code Online (Sandbox Code Playgroud)
这将运行所有 do-something s的一次,但有几个缺点,主要是做多岁的也有一些显著I/O执行其全部一次可能会慢一点.另一个问题是这个代码块立即返回,所以当所有的do-somethings完成时,没办法做其他工作.
你怎么写这个循环所以总是有X do-something一次运行?
Fri*_*ner 57
根据你想要做什么,xargs也可以提供帮助(这里:使用pdf2ps转换文档):
cpus=$( ls -d /sys/devices/system/cpu/cpu[[:digit:]]* | wc -w )
find . -name \*.pdf | xargs --max-args=1 --max-procs=$cpus pdf2ps
Run Code Online (Sandbox Code Playgroud)
来自文档:
--max-procs=max-procs
-P max-procs
Run up to max-procs processes at a time; the default is 1.
If max-procs is 0, xargs will run as many processes as possible at a
time. Use the -n option with -P; otherwise chances are that only one
exec will be done.
Run Code Online (Sandbox Code Playgroud)
Ole*_*nge 38
使用GNU Parallel http://www.gnu.org/software/parallel/,您可以编写:
some-command | parallel do-something
Run Code Online (Sandbox Code Playgroud)
GNU Parallel还支持在远程计算机上运行作业.这将在远程计算机上为每个CPU核心运行一个 - 即使它们具有不同数量的核心:
some-command | parallel -S server1,server2 do-something
Run Code Online (Sandbox Code Playgroud)
一个更高级的示例:这里我们列出了我们希望运行my_script的文件.文件有扩展名(可能是.jpeg).我们希望my_script的输出放在basename.out中的文件旁边(例如foo.jpeg - > foo.out).我们想为计算机的每个核心运行一次my_script,我们也希望在本地计算机上运行它.对于远程计算机,我们希望将文件处理传输到给定的计算机.当my_script完成时,我们希望将foo.out转回,然后我们要从远程计算机中删除foo.jpeg和foo.out:
cat list_of_files | \
parallel --trc {.}.out -S server1,server2,: \
"my_script {} > {.}.out"
Run Code Online (Sandbox Code Playgroud)
GNU Parallel确保每个作业的输出不会混合,因此您可以将输出用作另一个程序的输入:
some-command | parallel do-something | postprocess
Run Code Online (Sandbox Code Playgroud)
有关更多示例,请参阅视频:https://www.youtube.com/playlist?list = PL284C9FF2488BC6D1
小智 23
maxjobs=4
parallelize () {
while [ $# -gt 0 ] ; do
jobcnt=(`jobs -p`)
if [ ${#jobcnt[@]} -lt $maxjobs ] ; then
do-something $1 &
shift
else
sleep 1
fi
done
wait
}
parallelize arg1 arg2 "5 args to third job" arg4 ...
sko*_*ima 11
使用Makefile,而不是普通bash,然后指定同时作业make -jX的数量,其中X是一次运行的作业数.
或者您可以使用wait(" man wait"):启动多个子进程,调用wait- 它将在子进程完成时退出.
maxjobs = 10
foreach line in `cat file.txt` {
jobsrunning = 0
while jobsrunning < maxjobs {
do job &
jobsrunning += 1
}
wait
}
job ( ){
...
}
Run Code Online (Sandbox Code Playgroud)
如果需要存储作业的结果,则将其结果分配给变量.在wait您检查变量包含的内容之后.
Gru*_*bel 11
这里有一个替代解决方案,可插入.bashrc并用于日常一个班轮:
function pwait() {
while [ $(jobs -p | wc -l) -ge $1 ]; do
sleep 1
done
}
Run Code Online (Sandbox Code Playgroud)
要使用它,所有人必须做的是放在&作业和pwait调用之后,该参数给出了并行进程的数量:
for i in *; do
do_something $i &
pwait 10
done
Run Code Online (Sandbox Code Playgroud)
使用wait而不是忙于等待输出会更好jobs -p,但似乎没有明显的解决方案等待任何给定的作业完成而不是全部.
小智 8
也许尝试并行实用程序而不是重写循环?我是xjobs的忠实粉丝.我一直使用xjobs在我们的网络中批量复制文件,通常是在设置新的数据库服务器时. http://www.maier-komor.de/xjobs.html
虽然这样做bash可能是不可能的,但你可以很容易地做到半右派. bstark给出了合适的权利,但他有以下缺陷:
另一个没有这些缺陷的近似如下:
scheduleAll() {
local job i=0 max=4 pids=()
for job; do
(( ++i % max == 0 )) && {
wait "${pids[@]}"
pids=()
}
bash -c "$job" & pids+=("$!")
done
wait "${pids[@]}"
}
Run Code Online (Sandbox Code Playgroud)
请注意,此作业很容易适用于检查每个作业结束时的退出代码,以便您可以在作业失败时警告用户,或scheduleAll根据失败的作业数量设置退出代码等.
这段代码的问题就在于:
解决这个最后一个问题的解决方案必须用于kill -0轮询是否有任何进程已经消失而不是wait并安排下一个作业.但是,这引入了一个小问题:在作业结束和kill -0检查是否结束之间存在竞争条件.如果作业结束并且系统上的另一个进程同时启动,则采用恰好是刚刚完成的作业的随机PID,kill -0将不会注意到您的作业已完成并且事情将再次中断.
一个完美的解决方案是不可能的bash.
如果您熟悉该make命令,则大多数情况下您可以将要作为makefile运行的命令列表表达出来.例如,如果您需要在文件*.input上运行$ SOME_COMMAND,每个文件都生成*.output,您可以使用makefile
INPUT = a.input b.input
OUTPUT = $(INPUT:.input=.output)
%.output : %.input
$(SOME_COMMAND) $< $@
all: $(OUTPUT)
然后跑
make -j<NUMBER>
并行运行最多NUMBER个命令.