例子

例子

考虑以下场景。我有两个程序 A 和 B。程序 A 输出到 stdout 字符串行,而程序 B 处理来自 stdin 的字符串。这两个程序的使用方法当然是:

foo@bar:~$ A |乙

现在我注意到这只消耗了一个核心;因此我想知道:

程序 A 和 B 是否共享相同的计算资源?如果可以的话,有没有办法同时运行A和B?

我注意到的另一件事是 A 的运行速度比 B 快得多,因此我想知道是否可以以某种方式运行更多的 B 程序并让它们并行处理 A 输出的行。

也就是说,A 将输出其行,并且将有 N 个程序 B 实例读取这些行(无论谁先读取它们)处理它们并将它们输出到 stdout 上。

所以我的最后一个问题是:

有没有一种方法可以将输出通过管道传输到多个 B 进程中的 A,而不必考虑竞争条件和其他可能出现的不一致情况?

答案1

一个问题split --filter是输出可能会混合,因此您会从进程 1 中获得半行,然后从进程 2 中获得半行。

GNU Parallel 保证不会出现混淆。

所以假设你想做:

 A | B | C

但是 B 非常慢,因此您想要并行化它。然后你可以这样做:

A | parallel --pipe B | C

GNU Parallel 默认按 \n 分割,块大小为 1 MB。这可以通过 --recend 和 --block 进行调整。

您可以在以下位置找到有关 GNU Parallel 的更多信息:http://www.gnu.org/s/parallel/

您只需 10 秒即可安装 GNU Parallel:

$ (wget -O - pi.dk/3 || lynx -source pi.dk/3 || curl pi.dk/3/ || \
   fetch -o - http://pi.dk/3 ) > install.sh
$ sha1sum install.sh | grep 883c667e01eed62f975ad28b6d50e22a
12345678 883c667e 01eed62f 975ad28b 6d50e22a
$ md5sum install.sh | grep cc21b4c943fd03e93ae1ae49e28573c0
cc21b4c9 43fd03e9 3ae1ae49 e28573c0
$ sha512sum install.sh | grep da012ec113b49a54e705f86d51e784ebced224fdf
79945d9d 250b42a4 2067bb00 99da012e c113b49a 54e705f8 6d51e784 ebced224
fdff3f52 ca588d64 e75f6033 61bd543f d631f592 2f87ceb2 ab034149 6df84a35
$ bash install.sh

观看介绍视频http://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

答案2

当你写的时候A | B,两个进程已经并行运行。如果您看到它们仅使用一个核心,那可能是因为 CPU 关联性设置(也许有某种工具可以生成具有不同关联性的进程),或者因为一个进程不足以容纳整个核心,并且系统“宁愿”不分散计算。

要使用一个 A 运行多个 B,您需要一个工具,例如split带有--filter以下选项的工具:

A | split [OPTIONS] --filter="B"

然而,这可能会打乱输出中的行顺序,因为 B 作业不会以相同的速度运行。如果这是一个问题,您可能需要将第 B i 个输出重定向到中间文件,并在最后使用cat.反过来,这可能需要相当大的磁盘空间。

存在其他选项(例如,您可以将 B 的每个实例限制为单个行缓冲输出,等到 B 的整个“轮”完成,运行相当于减少split地图,以及cat临时输出),具有不同的效率水平。例如,刚刚描述的“round”选项将等待B 的最慢实例完成,因此它将很大程度上取决于 B 的可用缓冲;[m]buffer可能有帮助,也可能没有帮助,具体取决于操作的内容。

例子

生成前 1000 个数字并并行计算行数:

seq 1 1000 | split -n r/10 -u --filter="wc -l"
100
100
100
100
100
100
100
100
100
100

如果我们要“标记”这些行,我们会看到第一行被发送到进程 #1,第五行被发送到进程 #5,依此类推。此外,在生成第二个进程所需的时间内split,第一个进程已经是进入其配额的好方法了:

seq 1 1000 | split -n r/10 -u --filter="sed -e 's/^/$RANDOM - /g'" | head -n 10
19190 - 1
19190 - 11
19190 - 21
19190 - 31
19190 - 41
19190 - 51
19190 - 61
19190 - 71
19190 - 81

当在 2 核机器上执行时,seqsplit并且wc进程共享核心;但仔细观察,系统将前两个进程留在 CPU0 上,并将 CPU1 分配给工作进程:

%Cpu0  : 47.2 us, 13.7 sy,  0.0 ni, 38.1 id,  1.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu1  : 15.8 us, 82.9 sy,  0.0 ni,  1.0 id,  0.0 wa,  0.3 hi,  0.0 si,  0.0 st
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM     TIME+ COMMAND
 5314 lserni    20   0  4516  568  476 R 23.9  0.0   0:03.30 seq
 5315 lserni    20   0  4580  720  608 R 52.5  0.0   0:07.32 split
 5317 lserni    20   0  4520  576  484 S 13.3  0.0   0:01.86 wc
 5318 lserni    20   0  4520  572  484 S 14.0  0.0   0:01.88 wc
 5319 lserni    20   0  4520  576  484 S 13.6  0.0   0:01.88 wc
 5320 lserni    20   0  4520  576  484 S 13.3  0.0   0:01.85 wc
 5321 lserni    20   0  4520  572  484 S 13.3  0.0   0:01.84 wc
 5322 lserni    20   0  4520  576  484 S 13.3  0.0   0:01.86 wc
 5323 lserni    20   0  4520  576  484 S 13.3  0.0   0:01.86 wc
 5324 lserni    20   0  4520  576  484 S 13.3  0.0   0:01.87 wc

请特别注意,它split占用了大量的 CPU。这将根据 A 的需求按比例减少;即,如果 A 是一个比 更重的进程seq,则 的相对开销split将会减少。如果 A 是一个非常轻量级的进程,并且 B 非常快(因此您不需要超过 2-3 个 B 来与 A 保持一致),则与split(或一般情况下的管道)并行化可能不值得。

相关内容