使用os.pipe和os.fork()问题的Python程序

Par*_*dox 10 python fork pipe

我最近需要编写一个执行os.fork()的脚本来分成两个进程.子进程成为服务器进程,并使用os.pipe()创建的管道将数据传递回父进程.孩子关闭'r'管道的末端,父母'w'像往常一样关闭管道的末端.我将使用os.fdopen将pipe()的返回值转换为文件对象.

我遇到的问题是:流程成功分叉,孩子成为服务器.一切都很好,孩子尽职尽责地将数据写入'w'管道的开放端.不幸的是,管道的父端做了两件奇怪的事情:
A)它阻塞了管道末端的read()操作'r'.
其次,除非'w'结束完全关闭,否则它无法读取放在管道上的任何数据.

我立即认为缓冲是问题,并添加了pipe.flush()调用,但这些没有帮助.

任何人都可以解释为什么数据在写入结束完全关闭之前不会出现?是否存在使read()呼叫无阻塞的策略?

这是我的第一个分叉或使用管道的Python程序,如果我犯了一个简单的错误,请原谅我.

Bri*_*ian 12

您是在不指定大小的情况下使用read(),还是将管道视为迭代器(for line in f)?如果是这样,那可能是你的问题的根源 - read()被定义为在返回之前读取文件的末尾,而不是只读取可用于读取的内容.这意味着它将阻塞,直到孩子调用close().

在链接到的示例代码中,这没关系 - 父进程以阻塞方式运行,并且只是将子进程用于隔离目的.如果你想继续,那么要么使用非阻塞IO,就像你发布的代码一样(但是要准备处理半完成数据),或者读取块(例如r.read(size)或r.readline()) )只会在读取特定大小/行之前阻止.(你还需要给孩子打电话)

看起来将管道视为迭代器也使用了一些进一步的缓冲区,因为for line in r:如果您需要立即使用每条线路," "可能无法满足您的需求.有可能禁用它,但只是在fdopen中为缓冲区大小指定0似乎不够.

下面是一些应该有效的示例代码:

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)
Run Code Online (Sandbox Code Playgroud)


Par*_*dox 5

运用

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

在调用read()之前解决了这两个问题.read()调用不再阻塞,并且数据仅在写入端的flush()之后出现.


dF.*_*dF. 5

我看到你已经解决了阻塞 i/o 和缓冲的问题。

如果您决定尝试不同的方法,请注意: subprocess 是 fork/exec 惯用语的等效/替代品。这似乎不是你在做什么:你只有一个 fork(不是 exec)并在两个进程之间交换数据——在这种情况下,multiprocessing模块(在 Python 2.6+ 中)会更合适。