Pergunta

Eu precisava recentemente para escrever um script que executa um os.fork () se dividir em dois processos. O processo de criança se torna um processo de servidor e passa dados de volta para o processo pai usando um tubo criado com os.pipe () . A criança fecha a extremidade 'r' do tubo e o pai fecha a extremidade 'w' do tubo, como de costume. I converter os retornos de pipe () em objetos de arquivo com os.fdopen .

O problema que estou tendo é este: O processo bifurca com sucesso, e que a criança se torna um servidor. Tudo funciona muito bem ea criança escreve obedientemente dados ao final 'w' aberta do tubo. Infelizmente o fim pai do tubo faz duas coisas estranhas:
A) Ele bloqueia sobre a operação read() na extremidade 'r' do tubo.
Em segundo lugar, ele não consegue ler os dados que foi colocado no tubo, a menos que o fim 'w' está totalmente fechada.

pensei imediatamente que o buffer era o problema e acrescentou pipe.flush () chamadas, mas estes não ajudou.

Alguém pode lançar alguma luz sobre por que os dados não aparecer até o final de escrita está completamente fechada? E há uma estratégia para tornar o não bloqueio de chamadas read()?

Este é o meu primeiro programa Python que os tubos bifurcados ou usados, então me perdoe se eu cometi um erro simples.

Foi útil?

Solução

Você está usando read () sem especificar um tamanho, ou tratar o tubo como um iterador (for line in f)? Se assim for, essa é provavelmente a fonte do problema - leia () é definida para ler até o final do arquivo antes de retornar, em vez de ler apenas o que está disponível para leitura. Isso significa que ele irá bloquear até que a criança chama close ().

No código exemplo ligada a, este é OK - o pai está agindo de uma forma de bloqueio, e apenas usando a criança para fins de isolamento. Se você quiser continuar, em seguida, use non-blocking IO como no código que você postou (mas estar preparado para lidar com dados de meia-completo), ou ler em pedaços (por exemplo r.read (tamanho) ou r.readline () ) que vai bloquear somente até um tamanho específico / linha foi lido. (Você ainda precisará nivelado chamada sobre a criança)

Parece que tratar o tubo como um iterador está usando mais algum tampão, bem como, para "for line in r:" não pode dar o que você quer se você precisar de cada linha para ser imediatamente consumida. Pode ser possível desabilitar este, mas não apenas especificando 0 para o tamanho do buffer em fdopen não parece suficiente.

Aqui está um código de exemplo que deve funcionar:

import os, sys, time

r,w=os.pipe()
r,w=os.fdopen(r,'r',0), os.fdopen(w,'w',0)

pid = os.fork()
if pid:          # Parent
    w.close()
    while 1:
        data=r.readline()
        if not data: break
        print "parent read: " + data.strip()
else:           # Child
    r.close()
    for i in range(10):
        print >>w, "line %s" % i
        w.flush()
        time.sleep(1)

Outras dicas

Usando

fcntl.fcntl(readPipe, fcntl.F_SETFL, os.O_NONBLOCK)

Antes de chamar o read () resolveu os dois problemas. A chamada read () não está bloqueando e os dados são aparecendo depois de apenas um flush () no final da escrita.

Eu vejo você ter resolvido o problema de bloqueio de I / O e buffering.

Uma nota se você decidir tentar uma abordagem diferente: subprocesso é o equivalente / um substituto para o fork / exec idioma. Parece que isso não é o que está fazendo: você tem apenas um garfo (não um exec) e troca de dados entre os dois processos - neste caso, o multiprocessing módulo (em Python 2.6+) seria um ajuste melhor.

O "pai" vs. "criança" parte de garfo em um aplicativo de Python é bobagem. É um legado do Unix dias 16 bits. É uma afetação de um dia quando fork / exec e exec eram coisas importantes a fazer o máximo de um processador pequenino.

Quebre seu código Python em duas partes distintas:. Pais e filhos

A parte dos pais deve usar subprocess para executar a parte criança.

A fork e exec pode acontecer em algum lugar lá -. Mas você não precisa de cuidados

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top