2009-04-16 74 views
3

我有一个库的ctypes包装。不幸的是,这个库不是100%可靠的(偶尔会出现段错误等)。由于它的使用方式,我希望封装对图书馆崩溃具有相当的适应性。如何从分叉进程发送大量数据?

做到这一点的最好方法似乎是分离一个过程并将结果从孩子中发回。我想沿着这些线做些事情:

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) 

虽然这并不完美。分叉进程在写入时挂起。我是否试图一次发送太多?有一个更简单的解决方案来解决这个问题吗?

回答

4

也许您正在尝试编写比适合管道更多的数据,因此它会阻塞,直到有人出现并从中读取一些信息。这绝不会发生,因为唯一的读者是父进程,你似乎已经写了这个父进程来等待孩子在读取任何内容之前终止。这就是我们所说的死锁

您可能会考虑取出该os.waitpid调用,看看会发生什么。另一种选择是查看os.pipe是否有任何方法给它一个更大的缓冲区(我不知道你的环境足够说了)。

+3

+1:家长应持续阅读,直到EOF。当管道到达EOF时,这意味着孩子已完成(完成或坠毁)。 – 2009-04-16 19:18:53

0

一个解决这一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) 

waitpid函数与WNOHANG选项原因waitpid函数当子进程尚未退出立即返回。在这种情况下,它返回(0,0)。你需要确保每次通过循环覆盖结果变量,就像上面的代码一样。

2

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

  1. 发送少量数据。 zlib.compress可以帮助达到极限。
  2. 将实际数据存储在其他位置(文件,mmap,memcache),仅使用管道发送控制信息。
  3. 继续使用管道,但块输出。使用两套管道,以便进程可以相互通话并同步它们的通信。代码更复杂,但是非常有效。
+1

更少的数据 - 不合适。也许在别的地方存储。大块的输出 - 几乎没有必要。你需要一个选项4:父母从孩子读取输出 - 没什么奇特的 - 只读。 – 2009-04-16 19:58:55