Ignorando o buffer de saída subprocesso com popen em C ou Python
Pergunta
Eu tenho uma pergunta geral sobre popen (e todas as funções relacionadas), aplicável a todos os sistemas operacionais, quando eu escrever um script python ou algum código c e executar o executável resultante do console (ganhar ou linux), eu posso imediatamente ver a saída do processo. No entanto, se eu executar o mesmo executável como um processo bifurcada com a sua stdout redirecionado dentro de um tubo, os buffers de saída em algum lugar, geralmente até 4096 bytes antes de ser escrito para o tubo onde o processo pai pode lê-lo.
O seguinte script python irá gerar a saída em pedaços de 1024 bytes
import os, sys, time
if __name__ == "__main__":
dye = '@'*1024
for i in range (0,8):
print dye
time.sleep(1)
O seguinte script Python irá executar o script anterior e ler a saída, logo que se trata de tubo, byte por byte
import os, sys, subprocess, time, thread
if __name__ == "__main__":
execArgs = ["c:\\python25\\python.exe", "C:\\Scripts\\PythonScratch\\byte_stream.py"]
p = subprocess.Popen(execArgs, bufsize=0, stdout=subprocess.PIPE)
while p.returncode == None:
data = p.stdout.read(1)
sys.stdout.write(data)
p.poll()
Ajustar o caminho para o seu sistema operacional. Quando executado nesta configuração, a saída não será exibido em blocos de 1024, mas pedaços de 4096, apesar do tamanho do buffer do popen conjunto de comandos estar a 0 (que é o padrão de qualquer maneira). Alguém pode me dizer como alterar este comportamento ?, existe alguma maneira eu posso forçar o sistema operacional para tratar a saída do processo bifurcado da mesma maneira como quando ele é executado a partir do console ?, ou seja, apenas alimentar os dados através sem buffer?
Solução
Em geral, a biblioteca C de tempo de execução padrão (que está sendo executado em nome de praticamente todos os programas em todos os sistemas, mais ou menos ;-) detecta se stdout é um terminal ou não; se não, ele isola a saída (que pode ser um enorme ganho de eficiência, em comparação com a saída sem buffer).
Se você está no controle do programa que está fazendo a escrita, você pode (como uma outra resposta sugerida) nivelada stdout continuamente, ou (mais elegantemente se possível) tentar forçar stdout ser unbuffered, por exemplo, executando Python com a bandeira -u
linha de comando:
-u : unbuffered binary stdout and stderr (also PYTHONUNBUFFERED=x)
see man page for details on internal buffering relating to '-u'
(o que a página homem acrescenta uma menção de stdin e problemas com o modo binário [s]).
Se você não pode ou não quer tocar o programa que está escrevendo, -u
ou similar sobre o programa que está apenas a leitura é improvável que a ajuda (o buffer que mais importa é o que acontece no stdout do escritor, não aquele em stdin do leitor). A alternativa é para enganar o escritor em acreditar que ele está escrevendo a um terminal (embora na verdade ele está escrevendo para outro programa!), Através do módulo de biblioteca padrão pty
ou o terceiro nível mais alto pexpect módulo (ou, para Windows, o seu porto wexpect ).
Outras dicas
Isso é corrigir, e se aplica a Windows e Linux (e possivelmente outros sistemas), com popen()
e fopen()
. Se quiser que o buffer de saída para ser enviada antes de 4096 bytes, o uso fflush()
(em C) ou sys.stdout.flush()
(Python).