gpt4 book ai didi

bash - 并行运行一定数量的命令-对比xargs -P,GNU并行和“moreutils”并行

转载 作者:行者123 更新时间:2023-12-02 17:06:22 25 4
gpt4 key购买 nike

我正在尝试在bash脚本中的26台服务器上运行多个mongodump。

我可以运行3条命令,例如

mongodump -h staging .... &
mongodump -h production .... &
mongodump -h web ... &


同时,当一个完成时,我想启动另一个mongodump。

我无法同时运行所有26条mongodumps命令,服务器将在CPU上用尽。同时最多3个mongodumps。

最佳答案

您可以使用xarg-P选项并行运行指定数目的调用:

请注意,-P选项为not mandated by POSIX,但GNU xargs和BSD / macOS xargs均支持该选项。

xargs -P 3 -n 1 mongodump -h <<<'staging production web more stuff and so on'


这将并行运行 mongodump -h stagingmongodump -h productionmongodump -h web,等待所有3个调用完成,然后继续执行 mongodump -h moremongodump -h stuffmongodump -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'


现在,每个输入参数都用 {}代替,从而允许使用 after参数。

但是请注意,每条输入线总是作为单个参数传递。

BSD / macOS xargs允许您将 -n-J {}组合在一起,而无需提供基于行的输入,但是GNU xargs不支持 -J
简而言之:只有BSD / macOS允许您将输入参数的放置与一次读取多个参数结合起来。

请注意, xargs不会并行化命令并行输出的stdout输出,因此并行进程的输出可以交错访问。
使用GNU parallel可以避免此问题-参见下文。



备选: parallel

xargs具有成为标准实用程序的优势,因此在支持 -P的平台上没有先决条件。

在Linux世界中(尽管也通过 Homebrew在macOS上),有两个专门构建的实用程序,用于并行运行命令,但是它们具有相同的名称;通常,您必须按需安装它们:


parallel包中的 moreutils(二进制)-请参见 its home page
parallel包中的-更强大的-GNU parallel(Perl脚本),谢谢, twalberg。 -参见 its home page


如果您已经具有 parallel实用程序,则 parallel --version会告诉您它是哪个实用程序(GNU parallel报告版本号和版权信息,“ moreutils” parallel抱怨无效的选项并显示语法摘要) 。

使用“ moreutils” 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


xargs不同,此 parallel实现不采用从stdin传递的参数。所有传递参数必须在 --之后在命令行上传递。

据我所知,此 parallel实现提供的唯一功能超出了 xargs的功能:


-l选项允许延迟进一步的调用,直到系统负载超出指定的阈值以下为止。
可能是这样(来自 man页):“ stdout和stderr是通过相应的内部管道进行序列化的,以防止烦人的并发输出行为。”尽管我发现 man版本中的情况并非如此>页的日期为2009-07-2-请参阅最后一节。


使用GNU 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'



xargs一样,传递参数通过stdin提供,但是GNU parallel还支持在可配置的分隔符(默认为 :::)之后将其放在命令行中。
xargs不同,每个输入行都被视为单个参数。
警告:如果您的命令涉及带引号的字符串,则必须使用 -q将它们作为不同的参数传递;否则,请参见表11。例如, parallel -q sh -c 'echo hi, $0' ::: there仅与 -q一起使用。
与GNU xargs一样,您可以使用 -P 0一次运行尽可能多的调用,从而充分利用机器的功能,这意味着根据Ole的说法,“直到GNU Parallel达到极限(文件句柄和进程) ”。


方便地,省略 -P不仅像其他实用程序那样一次运行一个进程,而且每个CPU内核运行一个进程。

缺省情况下,并行执行的命令的输出默认在每个进程的基础上自动序列化(分组),以避免交错输出。


通常这是理想的,但是请注意,这意味着只有第一个创建输出的命令终止后,您才开始查看其他命令的输出。
使用选项 --line-buffer(在最新版本中为 --lb)选择退出此行为或
-u--ungroup)甚至允许一条输出线混合来自不同进程的输出;有关详细信息,请参见手册。



GNU parallel被设计为更好的 xargs的继任者,它提供了更多的功能:一个显着的例子是 perform sophisticated transformations on the pass-through arguments的功能,可以选择基于Perl正则表达式。另请参见: man parallelman parallel_tutorial



可选阅读:测试输出序列化行为

以下命令测试 xargs和两个 parallel实现如何处理并行运行的命令的交错输出-是否在到达时显示输出,或尝试对其进行序列化:

有2个级别的序列化,这两个级别都会带来开销:


行级序列化:防止将来自不同进程的部分行混合在单个输出行上。
流程级别的序列化:确保将给定流程的所有输出行组合在一起。
这是最用户友好的方法,但请注意,这意味着,只有第一个创建输出的命令终止后,您才可以开始(依次)查看其他命令的输出。


据我所知,只有GNU parallel提供任何序列化(尽管日期为2009-07-2的“ moreutils” parallel手册页说了什么[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"




xargs(GNU和BSD / macOS实施,在Ubuntu 16.04和macOS 10.12上均可找到):

不会发生序列化:单个输出行可以包含多个进程的输出。

$ 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




“ 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




GNU parallel(版本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




[1]“ stdout和stderr通过相应的内部管道进行序列化,以防止烦人的并发输出行为。”
告诉我我是否缺少什么。

关于bash - 并行运行一定数量的命令-对比xargs -P,GNU并行和“moreutils”并行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42651475/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com