将 stdin 复制到 stdout 和 stderr,但以同步方式

将 stdin 复制到 stdout 和 stderr,但以同步方式

我需要复制生产者的标准输出并将其提供给一个中的两个消费者同步的时尚。

                        consumer 1
producer | duplicator | 
                        consumer 2

这可以很容易地完成,例如通过tee

((cat f.txt | tee /dev/stderr | ./cons1.py >&3) 2>&1 | ./cons2.py) 3>&1

或通过命名管道:

mkfifo fifo1 fifo2
cat f.txt | tee fifo1 fifo2 >/dev/null &
< fifo1 ./cons1.py &
< fifo2 ./cons2.py

或者最后你可以编写一个dup.c程序来完成相同的工作:

#include <stdio.h>
int main()
{
    char *line = NULL;
    size_t size;
    while (getline(&line, &size, stdin) != -1) {
        fprintf(stdout, "%s", line);
        fprintf(stderr, "%s", line);
    }
    return 0;
}

进而:

((cat f.txt | ./dup | ./cons1.py >&3) 2>&1 | ./cons2.py) 3>&1

然而,如果消费者 1 比消费者 2 快,我们就会遇到问题。例如,消费者 1 已经位于第 50,000 行,而消费者 2 位于第 17,000 行。

对于我的系统我需要两个消费者都在同一条线上,因此需要限制更快的消费者。我知道通过 Linux 标准工具这可能是不可能的。然而,至少如果我们使用这种dup.c方法,它应该是可能的。有什么建议如何实现这一点?谢谢!

答案1

没有通用的方法可以完成您想要的事情。

基本问题是管道是一种单向的东西,生产者完全不知道消费者的当前状态,以及发送到管道的数据是否已经被消费。

因此,有两种方法可以解决此限制,并且都需要先验有关数据和消费者的知识:

  • 您使生产(或从原始生产者到消费者管道的运输)如此缓慢,以至于消费者始终保持同步,即在每条生产线被发送进行消费之后,您等待了很长时间,以至于消费者100%肯定已经完成发送下一行时进行处理(类似于 TiberiusKirk 的建议),

  • 您检查消费者中的处理进度,看看它们是否已经消耗了输入行(这需要消费者的反馈或输出,这些反馈或输出可能存在也可能不存在,并且可能会或可能不会被可行处理)。

第一个解决方法需要对输入数据的处理时间估计有一个适当的下限,第二个解决方法需要来自消费者的某种反馈。

答案2

您是否可以选择减慢文件的读取速度,从而迫使速度更快的消费者等待?

while read LINE; do
   echo "$LINE" | tee /dev/stderr | ./consumer1.py ; ) 2>&1 | ./consumer2.py
   sleep 0.01
done < "file.txt"

然而,在某些系统上,睡眠时间少于 1 秒并不是一个选项。

相关内容