Duplicar stdin para stdout e stderr, mas de forma sincronizada

1

Eu preciso duplicar o stdout de um produtor e alimentá-lo para dois consumidores de uma forma sincronizada .

                        consumer 1
producer | duplicator | 
                        consumer 2

Isso pode ser facilmente realizado, por exemplo, via tee:

(cat file.txt | tee /dev/stderr | ./consumer1.py ; ) 2>&1 | ./consumer2.py

ou por meio de pipes nomeados:

mkfifo myfifo
cat file.txt | tee myfifo | ./consumer1.py | ./consumer2.py < myfifo

ou finalmente você pode escrever um programa dup.c fazendo o mesmo trabalho:

#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;
}

e depois:

(cat file.txt | ./dup | ./consumer1.py ; ) 2>&1 | ./consumer2.py

No entanto, se o consumidor 1 for mais rápido que o consumidor 2, temos um problema . Por exemplo, o consumidor 1 já está na linha 50.000, enquanto o consumidor 2 está na linha 17.000.

Para meu sistema , preciso que os dois consumidores estejam na mesma linha, por isso, o consumidor mais rápido precisa ser restrito . Eu sei que isso pode ser impossível através de ferramentas padrão do Linux. No entanto, pelo menos se usarmos essa abordagem dup.c, ela deve ser de alguma forma possível. Alguma sugestão de como fazer isso? Obrigado!

    
por m33x 06.09.2015 / 14:06

2 respostas

2

Não há uma maneira geral de realizar o que você quer.

O problema básico é que um pipe é uma coisa unidirecional, e o produtor não tem absolutamente nenhum conhecimento sobre o estado atual do consumidor, e se os dados enviados para o pipe já foram consumidos ou não.

Existem duas maneiras de contornar essa limitação, e ambas exigem conhecimento a priori sobre os dados e os consumidores:

  • você faz a produção (ou o transporte do produtor original para os tubos dos consumidores) tão lenta que os consumidores estão sempre em sincronia, ou seja, depois de cada linha ser enviada para o consumo você espera tanto que os consumidores 100% certamente já terminou o processamento no momento em que a próxima linha é enviada (algo semelhante ao que foi sugerido por TiberiusKirk),

  • você verifica o progresso do processamento nos consumidores para ver se eles já consumiram as linhas de entrada (isso precisa de feedback ou saída dos consumidores, o que pode ou não existir, e pode ou não ser viável) processado).

A primeira solução precisa de um limite inferior adequado para a estimativa de tempo do processamento dos dados de entrada, a segunda alternativa precisa de algum tipo de feedback dos consumidores.

    
por 06.09.2015 / 15:39
0

Poderia ser uma opção para você desacelerar a leitura do arquivo, forçando assim o consumidor mais rápido a esperar?

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

No entanto, dormir menos de 1 segundo não é uma opção em alguns sistemas.

    
por 06.09.2015 / 14:47