当前位置:  开发笔记 > 编程语言 > 正文

使用最大进程数并行化Bash脚本

如何解决《使用最大进程数并行化Bash脚本》经验,为你挑选了8个好方法。

可以说我在Bash中有一个循环:

for foo in `some-command`
do
   do-something $foo
done

do-something是cpu绑定,我有一个漂亮闪亮的4核处理器.我希望能够一次跑到4 do-something岁.

天真的做法似乎是:

for foo in `some-command`
do
   do-something $foo &
done

这将运行所有 do-something s的一次,但有几个缺点,主要是做多岁的也有一些显著I/O执行其全部一次可能会慢一点.另一个问题是这个代码块立即返回,所以当所有的do-somethings完成时,没办法做其他工作.

你怎么写这个循环所以总是有X do-something一次运行?



1> Fritz G. Meh..:

根据你想要做什么,xargs也可以提供帮助(这里:使用pdf2ps转换文档):

cpus=$( ls -d /sys/devices/system/cpu/cpu[[:digit:]]* | wc -w )

find . -name \*.pdf | xargs --max-args=1 --max-procs=$cpus  pdf2ps

来自文档:

--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.


在我看来,这种方法是最优雅的解决方案.除了,因为我是偏执狂,我总是喜欢使用`find [...] -print0`和`xargs -0`.
`cpus = $(getconf _NPROCESSORS_ONLN)`

2> Ole Tange..:

使用GNU Parallel http://www.gnu.org/software/parallel/,您可以编写:

some-command | parallel do-something

GNU Parallel还支持在远程计算机上运行作业.这将在远程计算机上为每个CPU核心运行一个 - 即使它们具有不同数量的核心:

some-command | parallel -S server1,server2 do-something

一个更高级的示例:这里我们列出了我们希望运行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"

GNU Parallel确保每个作业的输出不会混合,因此您可以将输出用作另一个程序的输入:

some-command | parallel do-something | postprocess

有关更多示例,请参阅视频:https://www.youtube.com/playlist?list = PL284C9FF2488BC6D1



3> 小智..:
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 ...


意识到这里有一些**严重**的不足之处,所以任何需要参数空间的工作都会失败; 此外,如果请求的工作量超过maxjobs允许的话,这个脚本会等待一些工作完成,从而使你的CPU活着.

4> skolima..:

使用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 ( ){
...
}

如果需要存储作业的结果,则将其结果分配给变量.在wait您检查变量包含的内容之后.



5> Grumbel..:

这里有一个替代解决方案,可插入.bashrc并用于日常一个班轮:

function pwait() {
    while [ $(jobs -p | wc -l) -ge $1 ]; do
        sleep 1
    done
}

要使用它,所有人必须做的是放在&作业和pwait调用之后,该参数给出了并行进程的数量:

for i in *; do
    do_something $i &
    pwait 10
done

使用wait而不是忙于等待输出会更好jobs -p,但似乎没有明显的解决方案等待任何给定的作业完成而不是全部.



6> 小智..:

也许尝试并行​​实用程序而不是重写循环?我是xjobs的忠实粉丝.我一直使用xjobs在我们的网络中批量复制文件,通常是在设置新的数据库服务器时. http://www.maier-komor.de/xjobs.html



7> lhunath..:

虽然这样做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[@]}"
}

请注意,此作业很容易适用于检查每个作业结束时的退出代码,以便您可以在作业失败时警告用户,或scheduleAll根据失败的作业数量设置退出代码等.

这段代码的问题就在于:

它一次安排四个(在这种情况下)作业,然后等待所有四个结束.有些可能比其他一些更快完成,这将导致下一批四个作业等到上一批的最长时间完成.

解决这个最后一个问题的解决方案必须用于kill -0轮询是否有任何进程已经消失而不是wait并安排下一个作业.但是,这引入了一个小问题:在作业结束和kill -0检查是否结束之间存在竞争条件.如果作业结束并且系统上的另一个进程同时启动,则采用恰好是刚刚完成的作业的随机PID,kill -0将不会注意到您的作业已完成并且事情将再次中断.

一个完美的解决方案是不可能的bash.



8> Idelic..:

如果您熟悉该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个命令.

推荐阅读
贴进你的心聆听你的世界
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有