从多个 fifo 并行读取非阻塞

Ole*_*nge 7 merge cat parallel-processing fifo

有时我会坐在一堆并行运行的程序的输出先进先出。我想合并这些先进先出。天真的解决方案是:

cat fifo* > output
Run Code Online (Sandbox Code Playgroud)

但这需要第一个fifo在从第二个fifo读取第一个字节之前完成,这会阻塞并行运行的程序。

另一种方式是:

(cat fifo1 & cat fifo2 & ... ) > output
Run Code Online (Sandbox Code Playgroud)

但这可能会混合输出,从而在输出中得到半行。

当从多个fifos读取时,必须有一些合并文件的规则。通常逐行执行它对我来说就足够了,所以我正在寻找可以做的事情:

parallel_non_blocking_cat fifo* > output
Run Code Online (Sandbox Code Playgroud)

它将并行读取所有先进先出,并一次将输出与整行合并。

我可以看到编写该程序并不难。您需要做的就是:

  1. 打开所有先进先出
  2. 对所有这些进行阻塞选择
  3. 从具有数据的 fifo 中非阻塞地读取到该 fifo 的缓冲区中
  4. 如果缓冲区包含完整的行(或记录),则打印出该行
  5. 如果所有fifos都关闭/eof:退出
  6. 转到 2

所以我的问题不是:可以做到吗?

我的问题是:它已经完成了吗,我可以安装一个工具来做到这一点吗?

Ole*_*nge 2

仅当 fifo 的数量少于 GNU 并行可以并行运行的作业数量(受文件句柄和进程数量限制)时,此解决方案才有效:

parallel -j0 --line-buffer cat ::: fifo*
Run Code Online (Sandbox Code Playgroud)

它似乎能够移动到 500 MB/s:

window1$ mkfifo {1..100}
window1$ parallel -j0 --line-buffer cat ::: {1..100} | pv >/dev/null

window2$ parallel -j0 'cat bigfile > ' ::: *
Run Code Online (Sandbox Code Playgroud)

并且它不混合半行:

window1$ mkfifo {1..100}
window1$ parallel -j0 --line-buffer cat ::: {1..100} &

window2$ parallel -j0 'traceroute {}.1.1.1 > {}' ::: *
Run Code Online (Sandbox Code Playgroud)

它并行读取作业(在转到下一个作业之前不会完全读取一个作业):

window1$ mkfifo {1..100}
window1$ parallel -j0 --line-buffer cat ::: * > >(tr -s ABCabc)

window2$ long_lines_with_pause() {
            perl -e 'print STDOUT "a"x30000_000," "'                                                      
    perl -e 'print STDOUT "b"x30000_000," "'                                                      
    perl -e 'print STDOUT "c"x30000_000," "'                                                      
    echo "$1"                                                                                     
    sleep 2                                                                                       
    perl -e 'print STDOUT "A"x30000_000," "'                                                      
    perl -e 'print STDOUT "B"x30000_000," "'                                                      
    perl -e 'print STDOUT "C"x30000_000," "'                                                      
    echo "$1"                                                                                     
}
window2$ export -f long_lines_with_pause
window2$ parallel -j0 'long_lines_with_pause {} > {}' ::: *
Run Code Online (Sandbox Code Playgroud)

这里,很多“ab c”(作业的前半部分)将在“ABC”(作业的后半部分)之前打印。