如何并行运行多个 pv 命令?

如何并行运行多个 pv 命令?

pv我想在每个管道上运行一系列命令管道。这是一个例子:

for p in 1 2 3
do
  cat /dev/zero | pv -N $p | dd of=/dev/null &
done

管道中的实际命令并不重要(cat/dd只是一个示例)...

目标是 4 个并发运行的管道,每个管道都有自己的pv输出。然而,当我尝试将这样的命令置于后台时,pv会停止,我得到的只是 4 个停止的作业。我试过了{...|pv|...}&bash -c "...|pv|..." &结果都一样。

如何pv同时运行多个命令管道?

答案1

发现我可以使用xargs以下-P选项来做到这一点:

josh@subdivisions:/# seq 1 10 | xargs -P 4 -I {} bash -c "dd if=/dev/zero bs=1024 count=10000000 | pv -c -N {} | dd of=/dev/null"
        3: 7.35GiB 0:00:29 [ 280MiB/s] [                                                                                         <=>                                                                 ]
        1: 7.88GiB 0:00:29 [ 312MiB/s] [                                                                                         <=>                                                                 ]
        4: 7.83GiB 0:00:29 [ 258MiB/s] [                                                                                         <=>                                                                 ]
        2: 6.55GiB 0:00:29 [ 238MiB/s] [                                                                                         <=>                                                                 ]

发送数组的输出以迭代到xargs;的 stdin 中要同时运行所有命令,请使用-P 0

答案2

pv无法在后台启动。

src/main/main.c正如您在源代码的文件中看到的,他们在终端上pv设置标志(在结构的中)。他们这样做是为了在不在前台时尝试写入终端时接收到,用信号处理程序捕获它,并将输出重定向到以免“弄乱”终端。TOSTOPtcsetattr()c.c_lflagtermiosSIGTTOU/dev/null

/*
 * Set terminal option TOSTOP so we get signal SIGTTOU if we try to
 * write to the terminal while backgrounded.
 *
 * Also, save the current terminal attributes for later restoration.
 */
memset(&t, 0, sizeof(t));
tcgetattr(STDERR_FILENO, &t);
t_save = t;
t.c_lflag |= TOSTOP;
tcsetattr(STDERR_FILENO, TCSANOW, &t);

这当然很恶心,因为它不只是为自己设置该标志,而是为所有使用终端的程序设置该标志。

但这还不是全部。正如 glibc 中所解释的手动的:

函数:int tcsetattr(int filedes, int when, const struct termios *termios-p)

如果从其控制终端上的后台进程调用此函数,通常会向进程组中的所有进程发送 SIGTTOU 信号,就像进程尝试写入终端一样。例外情况是调用进程本身忽略或阻止 SIGTTOU 信号,在这种情况下将执行操作但不会发送信号。请参阅作业控制。

他们没有阻止或忽略SIGTTOU.而且他们也没有检查tcsetattr()( 它将返回 -1 并设置errnoEINTR 如果他们SIGTTOU之前已经设置了信号处理程序)。

因此该过程被停止。如果它收到一个SIGCONT(来自bg命令),它将在尝试完成tcsetattr().

所以我想你应该将其视为一项功能;-)

相关内容