bas*_*nte 4 parallel-processing bash xargs gnu-parallel
我试图在bash脚本中在26台服务器上运行多个mongodump.
我可以运行3个命令
mongodump -h staging .... &
mongodump -h production .... &
mongodump -h web ... &
同时,当一个人完成时,我想开始另一个mongodump.
我无法同时运行所有26个mongodumps命令,服务器将在CPU上运行.最多3个mongodumps同时.
您可以使用xarg的-P选项,以运行并行调用的可指定号码:
请注意,该-P选项不是POSIX强制要求的,但GNU xargs和BSD/macOS都xargs支持它.
xargs -P 3 -n 1 mongodump -h <<<'staging production web more stuff and so on'
Run Code Online (Sandbox Code Playgroud)
这将运行mongodump -h staging, mongodump -h production以及 mongodump -h web并行,等待所有3个电话到结束,然后继续mongodump -h more, mongodump -h stuff和 mongodump -h and,等等.
-n 1抓起单从输入流和呼叫参数mongodump; 如有必要,根据需要调整输入中的单引号或双引号.
注:GNU xargs -但不是BSD xargs-支持-P 0,这里0表示:"同时运行尽可能多的进程尽可能"
默认情况下,通过stdin提供的参数将附加到指定的命令.
如果需要控制在生成的命令中放置相应参数的位置,
-I {}指示,并定义{}为每个输入行的占位符.xargs -P 3 -I {} mongodump -h {} after <<<$'staging\nproduction\nweb\nmore\nstuff'
Run Code Online (Sandbox Code Playgroud)
现在每个输入参数都被替换{},允许参数after后来.
但请注意,每个输入行总是作为单个参数传递.
BSD/macOS xargs允许你结合-n使用-J {},而不需要提供基于行的输入,但GNU xargs不支持-J.
简而言之:只有BSD/macOS允许您将输入参数的放置与一次读取多个参数组合在一起.
请注意,xargs并没有序列从并行命令标准输出的输出,使从并行处理输出可以到达交错.
使用GNU parallel来避免这个问题 - 见下文.
parallelxargs具有作为标准实用程序的优点,因此在它支持的平台上-P,没有先决条件.
在Linux世界中(虽然也通过Homebrew上的macOS )有两个专门用于并行运行命令的实用程序,不幸的是,它们共享相同的名称; 通常,您必须按需安装它们:
如果您已经有一个parallel实用程序,parallel --version它将告诉您它是哪一个(GNU parallel报告版本号和版权信息,"moreutils" parallel抱怨无效选项并显示语法摘要).
parallel:parallel -j 3 -n 1 mongodump -h -- staging production web more stuff and so on
# Using -i to control placement of the argument, via {}
# Only *1* argument at at time supported in that case.
parallel -j 3 -i mongodump -h {} after -- staging production web more stuff and so on
Run Code Online (Sandbox Code Playgroud)
与xargs此不同,此parallel实现不会将参数从stdin传递出去; 必须在命令行上传递所有传递参数,如下所示--.
据我所知,parallel除了xargs可以做的以外,这个实现提供的唯一功能是:
-l选项允许延迟进一步的调用,直到系统加载超额低于指定的阈值.man页面):"stdout和stderr是通过相应的内部管道序列化的,以防止令人讨厌的并发输出行为."虽然我发现在页面日期为2009- 的版本中并非如此man- 07-2 - 见最后一节.parallel:给Ole Tange的帽子提示他的帮助.
parallel -P 3 -n 1 mongodump -h <<<$'staging\nproduction\nweb\nmore\nstuff\nand\nso\non'
# Alternative, using ::: followed by the target-command arguments.
parallel -P 3 -n 1 mongodump -h ::: staging production web more stuff and so on
# Using -n 1 and {} to control placement of the argument.
# Note that using -N rather than -n would allow per-argument placement control
# with {1}, {2}, ...
parallel -P 3 -n 1 mongodump -h {} after <<<$'staging\nproduction\nweb\nmore\nstuff\nand'
Run Code Online (Sandbox Code Playgroud)
与之一样xargs,传递参数是通过stdin提供的,但是GNU parallel还支持在可配置的分隔符(:::默认情况下)之后将它们放在命令行上.
与之不同xargs,每个输入行被视为单个参数.
警告:如果你的命令涉及带引号的字符串,你必须使用-q它们作为不同的参数传递它们; 例如,parallel -q sh -c 'echo hi, $0' ::: there只适用于-q.
与GNU xargs,你可以使用-P 0运行尽可能多的调用尽可能一次,取本机的功能和优势,这意味着,根据OLE"直到GNU并行击中限制(文件句柄和工艺)".
-P不只是运行一个在一个时间过程中,由于其他实用程序做,但运行一个进程每个CPU核心.默认情况下,并行执行的命令输出会按进程自动序列化(分组),以避免交错输出.
--line-buffer(--lb在更新的版本中)选择退出此行为或-u(--ungroup)以允许甚至单个输出行混合来自不同进程的输出; 有关详细信息,请参阅手册GNU parallel,旨在成为更好的继承者xargs,提供了更多的功能:一个值得注意的例子是能够对传递参数执行复杂的转换,可选择基于Perl 正则表达式 ; 另见:man parallel和man parallel_tutorial.
以下命令测试xargs两个parallel实现如何处理并行运行的命令的交错输出 - 无论它们是在到达时显示输出还是尝试序列化它:
有两个级别的序列化,这两个级别都引入了开销:
行级序列化:防止来自不同进程的部分行在单个输出行上混合.
进程级序列化:确保将给定进程的所有输出行组合在一起.
这是用户最友好的方法,但请注意,这意味着只有在创建输出的第一个命令终止后,您才会开始看到其他命令的输出(按顺序).
据我所知,只有GNU parallel提供任何序列化(尽管parallel2009-07-2 所述的"moreutils" 手册页[1]
),它支持这两种方法.
以下命令假定存在可执行脚本,./tst其中包含以下内容:
#!/usr/bin/env bash
printf "$$: [1/2] entering with arg(s): $*"
sleep $(( $RANDOM / 16384 ))
printf " $$: [2/2] finished entering\n"
echo " $$: stderr line" >&2
echo "$$: stdout line"
sleep $(( $RANDOM / 8192 ))
echo " $$: exiting"
Run Code Online (Sandbox Code Playgroud)
xargs (在Ubuntu 16.04和macOS 10.12上都可以找到GNU和BSD/macOS实现):
不会发生序列化:单个输出行可以包含来自多个进程的输出.
$ xargs -P 3 -n 1 ./tst <<<'one two three'
2593: [1/2] entering with arg(s): one2594: [1/2] entering with arg(s): two 2593: [2/2] finished entering
2593: stderr line
2593: stdout line
2596: [1/2] entering with arg(s): three 2593: exiting
2594: [2/2] finished entering
2594: stderr line
2594: stdout line
2596: [2/2] finished entering
2596: stderr line
2596: stdout line
2594: exiting
2596: exiting
Run Code Online (Sandbox Code Playgroud)
"moreutils"parallel(man页面日期为2009-07-02)
不会发生序列化:单个输出行可以包含来自多个进程的输出.
$ parallel -j 3 ./tst -- one two three
3940: [1/2] entering with arg(s): one3941: [1/2] entering with arg(s): two3942: [1/2] entering with arg(s): three 3941: [2/2] finished entering
3941: stderr line
3941: stdout line
3942: [2/2] finished entering
3942: stderr line
3942: stdout line
3940: [2/2] finished entering
3940: stderr line
3940: stdout line
3941: exiting
3942: exiting
Run Code Online (Sandbox Code Playgroud)
GNUparallel(版本20170122)
默认情况下会发生进程级序列化(分组).使用--line-buffer(--lb在较新的版本中)来选择行级序列化,或者选择退出任何类型的序列化-u
(--ungroup).
请注意,在每个组中,stderr输出是在 stdout输出之后出现的(而版本20170122附带的手册页声称stderr输出首先出现).
$ parallel -P 3 ./tst ::: one two three
2544: [1/2] entering with arg(s): one 2544: [2/2] finished entering
2544: stdout line
2544: exiting
2544: stderr line
2549: [1/2] entering with arg(s): three 2549: [2/2] finished entering
2549: stdout line
2549: exiting
2549: stderr line
2546: [1/2] entering with arg(s): two 2546: [2/2] finished entering
2546: stdout line
2546: exiting
2546: stderr line
Run Code Online (Sandbox Code Playgroud)
[1]"stdout和stderr通过相应的内部管道序列化,以防止恼人的并发输出行为."
告诉我我是否遗漏了什么.
如果您只是排除每第三个&(或者如果全部都在一行上则使用 a ;),那么它将不会并行执行整个过程。
例如:
echo "Hello" & sleep 1 ;
echo "Hello Again" & sleep 1 ;
echo "Once More" & sleep 1 ;
Run Code Online (Sandbox Code Playgroud)