使用“tee”、fifos 和“paste”的分支数据流有什么问题?

使用“tee”、fifos 和“paste”的分支数据流有什么问题?

本着这个问题,我想从单个源创建分支数据流:

cmd1 ──> tee ──────────────> │          
         ├─────> cmd2 ─────> │ cmd4  
         └─────> cmd3 ─────> │

与这个问题不同,我希望我的输出是交错的,而不是一次一个命令。我可以使用命名管道来做到这一点paste

$ mkfifo fifo1 fifo2
$ seq 1 100 \
    | tee \
      >(awk '$0+=1' > fifo1) \
      >(awk '$0+=2' > fifo2) \
    | paste - fifo1 fifo2

这似乎工作正常;即,它打印

1 2 3
2 3 4
...
100 101 102

这是一个说明该概念的概念示例。我的真实的管道看起来像这样:

find "$1" -type d -print0 \
  | tee \
    >(xargs -0 -n1 du -bs | cut -f1 > fifo1) \
    >(xargs -0 -n1000 stat --printf="%G\n" > fifo2) \
  | xargs -0 -n1 echo \
  | paste - fifo1 fifo2

在大多数情况下,这似乎也工作得很好。但是当我在一个巨大的文件系统上运行它时,它最终挂在中间。通过阅读上面的问题,我怀疑我发生了僵局。但我不太明白它可能在哪里——似乎paste应该保持所有数据的流动。

我想我仍然不明白缓冲和数据流tee、管道和fifos。谁能解释一下我在这里缺少什么?堵塞在哪里以及如何修复? (或者进一步调查?)

答案1

并行写入和读取管道需要严格的纪律。

假设一个管道可以缓冲 128KBytes。现在假设所有文件名的长度均为 1 MB。文件名不适合管道,因此读者必须先读取一些内容,然后才能写入其余部分。但如果读者当前正在等待来自另一个管道的输入,则这种情况永远不会发生。

在您的示例中,xargs -n1000将在输出任何内容之前读取 1000MBytes,因此paste将等待 $fifo2whiletee尝试写入 stdout 的输入。

试试这个:

du_cut() { du -bs "$1" | cut -f1; }
stat_print() { stat --printf="%G\n" "$1"; }
doit() { printf "%s\t%s\n" $(du_cut "$1") $(stat_print "$1"); }
export -f du_cut stat_print doit
find "$1" -type d -print0 | parallel -0 --tag doit

相关内容