Shell 有没有像xargs这样的东西,它通过管道传输数据而不是使用参数?
Shell 有没有像xargs这样的东西,它通过管道传输数据而不是使用参数?,shell,parallel-processing,xargs,Shell,Parallel Processing,Xargs,xargs如果您有一个通过命令行参数接受其输入的命令,那么它非常有用,但是如果您有一个通过stdin接受其输入的命令,那么它就没有那么有用了 我所看到的对于这种情况的建议是使用tee将行复制到几个下游进程,如下所示: producer | tee>(consumer0>out0)>(consumer1>out1)>(consumer2>out2)| consumer3>out3; cat out*|管道的下一阶段 这有一个缺点,即所有消费者都会收到所有生成的行,并且假设消费者{0..3}是不同
xargs
如果您有一个通过命令行参数接受其输入的命令,那么它非常有用,但是如果您有一个通过stdin接受其输入的命令,那么它就没有那么有用了
我所看到的对于这种情况的建议是使用tee
将行复制到几个下游进程,如下所示:
producer | tee>(consumer0>out0)>(consumer1>out1)>(consumer2>out2)| consumer3>out3;
cat out*|管道的下一阶段
这有一个缺点,即所有消费者都会收到所有生成的行,并且假设消费者{0..3}
是不同的过程。如果我需要每个消费者都是相同的,并且处理部分输入(例如,并行化一个顺序消费者),那么它就不能正常工作
我要寻找的是一种类似于xargs
的东西,它允许在同一消费者的多个实例之间分割工作,然后组合输入和继续处理。输出的组合方式应该模仿xargs,因此不能保证行的顺序,但两行不会拼接在一起(例如:“Hello Fred”和“Hello George”可能以任何顺序出现,但您不会看到“HHello GeoFregedello”)
这样做的主要用途是处理大量数据,如果为每行输入旋转一次,那么用户的启动延迟将是显而易见的。如果consumer
的启动成本不高,我只需将其封装在一个小的shell脚本中,将其参数导入consumer
并使用xargs
调用即可
至少在我想到的用例中,生产者将从内部服务获取一组数据,之后消费者将需要转换这些数据并进行一些API调用。因此,生产者和消费者都将是长时间运行的进程,并行运行API调用确实会加快速度
像这样的东西很理想,但我找不到任何能做到这一点的东西:
producer |-P20用户|管道的下一阶段
是否有提供此功能的命令行工具
在同一使用者的多个实例之间拆分工作
这可以在xargs
的消费者端完成
例:
将随机选择一个消费者
委员会:
将为每个使用者运行输入
不管怎样,你应该明白这个想法
对于您的T恤,无需任何临时文件即可轻松完成:
consumer() { sed "s/^/$1: /"; }
producer() { seq 3; }
next-stage-of-pipeline() { sed "s/^/Result: /"; }
producer |
{ tee >(consumer 0 >&10) >(consumer 1 >&11) >(consumer 2 >&12) | consumer 3 >&14 ;} 10>&1 11>&1 12>&1 14>&1 |
next-stage-of-pipeline
如果您需要ex.为每个消费者将输入拆分为4,那么仍然很容易做到:
filter() { awk -vN="$1" '(NR + N) % 4 == 1'
producer |
{ tee >(
filter 1 | consumer 0 >&10
) >(
filter 2 | consumer 1 >&11
) >(
filter 3 | consumer 2 >&12
) |
filter 4 | consumer 3 >&14
;} 10>&1 11>&1 12>&1 14>&1 |
next-stage-of-pipeline
我认为,
gnuparallel
可能会满足您的需求
producer | parallel consumer | next command in pipeline
编辑:直到我开始玩parallel
,我才完全理解这个问题。Parallel可以将函数作为消费者,您可以在该函数中使用流
e、 g
编辑2:
您可以使用--pipe
选项,该选项将数据传输到使用者。-q
参数在使用者周围放置shell引号:
for i in {1..30}; do echo "foo $i bar"; done | parallel --pipe -q awk '{print $2}'
奖金:
parallel
将在顺序处理器上运行作业。如果您有8个核心和16个消费者,每个核心将有2个消费者(这是可配置的)parallel
可以在网络上的多台机器上运行,只要它可以ssh
发送到这些机器而不需要提示输入密码(例如,使用ssh代理
)GNU Parallel可以将标准输入切碎到同一个命令:
... | parallel --pipe consumer
默认情况下,它在\n
上进行剪切,块大小约为1MB。这可以通过--recstart
/--recend
和--block
进行更改
如果输入是文件,则速度更快:
parallel -a bigfile --pipepart --block -1 consumer
这将找到bigfile
的大小,并为每个CPU线程将其拆分为一个块。这是动态完成的,因此不会创建临时文件
的第9章详细介绍了这一点
但如果您真的希望整个输入通过管道传输到不同的用户,GNU Parallel也可以做到这一点:
# Pipe 1..10 to consumer-a..z
seq 10 | parallel --pipe --tee 'echo consumer-{}; cat' ::: {a..z}
您打算如何分割输入?逐行循环?第一个1/20到消费者0,下一个1/20到消费者1。。。?如何组合输出?理想情况下,它是可配置的,实际上,循环是最容易实现的,如果有这样一个工具,我所期望的可能是可用的(我认为这就是xargs如何将输入拆分为参数)。为了在存在大量输入的情况下以合理的方式进行操作,我希望输出不会提供任何保证,除了当作为工具stdout(基本上是xargs的行为)发出时不会混合行(空定界选项会很好),我不理解。如果
consumer
的速度很快,你就不能使用xargs-p20bash-c'consumer@KamilCuk,但是如果你使用像Java这样的语言编写的东西,这就不太理想了,因为它既有启动成本,而且运行时间越长,速度就越快。@Morgen为了避免额外的混乱,您能否澄清“生产者”是否“昂贵”(时间、内存、启动缓慢等),以及预期产生的数据量。让消费者/生产者并行运行很重要吗?我认为有一点需要注意,在POSIX系统上,只有当小于PIPE_BUF(例如,默认情况下没有缓冲stderr)时,才能保证缓冲写入是原子的。虽然我喜欢这是一个纯shell解决方案,但它不能很好地扩展到约20个消费者(当你必须重复几乎相同的代码时,很容易打错字)(…)
不能缩放,而且从来没有缩放过。你可以在awk
tho中做管道,所以你可以试试。除此之外,我想我们必须编写我们自己的工具来完成。但是,例如,最后一个代码片段能做到你想的吗?拆分
... | parallel --pipe consumer
parallel -a bigfile --pipepart --block -1 consumer
# Pipe 1..10 to consumer-a..z
seq 10 | parallel --pipe --tee 'echo consumer-{}; cat' ::: {a..z}