Python 如何从分叉流程发送大量数据?

Python 如何从分叉流程发送大量数据?,python,fork,pipe,Python,Fork,Pipe,我有一个用于库的ctypes包装器。不幸的是,该库不是100%可靠的(偶尔出现SEGFULTS等)。由于它的使用方式,我希望包装器对库崩溃具有合理的弹性 最好的方法似乎是分岔一个过程,并将结果从孩子那里发回。我想做以下几点: r, w = os.pipe() pid = os.fork() if pid == 0: # child result = ctypes_fn() os.write(w, pickle.dumps(result)) os.close(w)

我有一个用于库的ctypes包装器。不幸的是,该库不是100%可靠的(偶尔出现SEGFULTS等)。由于它的使用方式,我希望包装器对库崩溃具有合理的弹性

最好的方法似乎是分岔一个过程,并将结果从孩子那里发回。我想做以下几点:

r, w = os.pipe()
pid = os.fork()

if pid == 0:
    # child
    result = ctypes_fn()
    os.write(w, pickle.dumps(result))
    os.close(w)
else:
    # parent
    os.waitpid(pid, 0)
    result = os.read(r, 524288) # can be this big
    os.close(r)

    return pickle.loads(result)

不过,这不太管用。分叉进程挂起在写操作上。我是不是想一下子寄太多?这个问题有更简单的解决方案吗?

可能您试图写入的数据超过了管道的容量,因此它会一直阻塞,直到有人过来读取其中的一些信息。这种情况永远不会发生,因为唯一的读取器是父进程,您编写该进程似乎是为了等到子进程终止后再读取任何内容。这就是我们所说的僵局


你可以考虑取出那个OS.WITPID呼叫,看看会发生什么。另一个选择是查看os.pipe是否有任何方法可以为其提供更大的缓冲区(我对您的环境还不太了解)。

ted.dennison提到的死锁解决方案是以下伪代码:

#parent
while waitpid(pid, WNOHANG) == (0, 0):
    result = os.read(r, 1024)
    #sleep for a short time
#at this point the child process has ended 
#and you need the last bit of data from the pipe
result = os.read(r, 1024)
os.close(r)

带有WNOHANG选项的Waitpid会在子进程尚未退出时立即返回Waitpid。在本例中,它返回(0,0)。您需要确保不要像上面的代码那样每次通过循环都覆盖结果变量。

基本问题是管道上有64kB的限制。从简单到复杂,有几种可能的解决方案:

  • 发送更少的数据。zlib.compress有助于降低限制
  • 将实际数据存储在其他位置(文件、mmap、memcache),仅使用管道发送控制信息
  • 继续使用管道,但将输出分块。使用两组管道,以便进程可以相互通信并同步其通信。代码更复杂,但在其他方面非常有效

  • +1:家长应持续阅读,直到EOF。当管道到达EOF时,这意味着子级已完成(完成或崩溃)。数据较少——不合适。也许可以去别的地方。将输出分块——几乎没有必要。您需要一个选项4:父级读取子级的输出——没什么特别的——只是读取。共享内存也可以用于发送大量数据。