【问题标题】:How do I send large amounts of data from a forked process?如何从分叉进程发送大量数据?
【发布时间】:2009-04-16 16:47:21
【问题描述】:

我有一个库的 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)

不过,这并不完全奏效。分叉的进程在写入时挂起。我想一次发送太多吗?这个问题有更简单的解决方案吗?

【问题讨论】:

    标签: python fork pipe


    【解决方案1】:

    可能您正在尝试写入的数据超出管道的容量,因此它会阻塞,直到有人出现并从那里读取其中的一些信息。这永远不会发生,因为唯一的读取器是父进程,您似乎已经编写了它以等待子进程终止,然后再读取任何内容。这就是我们所说的死锁

    您可以考虑取消 os.waitpid 调用,看看会发生什么。另一种选择是查看 os.pipe 是否有任何方法可以为其提供更大的缓冲区(我不知道你的环境足以说明)。

    【讨论】:

    • +1:父母应该连续阅读直到 EOF。当管道到达 EOF 时,这意味着子进程已完成(完成或崩溃)。
    【解决方案2】:

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

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

    【讨论】:

    • 数据较少——不合适。存储在其他地方,也许。分块输出——几乎没有必要。你需要一个选项 4:父母从孩子那里读取输出——没什么特别的——只是阅读。
    • 共享内存也可以用来发送大量数据。
    【解决方案3】:

    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)。您需要确保不要像上面的代码那样每次通过循环覆盖结果变量。

    【讨论】:

      猜你喜欢
      • 2010-11-07
      • 2013-07-17
      • 1970-01-01
      • 2011-08-15
      • 1970-01-01
      • 1970-01-01
      • 2022-01-15
      • 1970-01-01
      • 2013-04-08
      相关资源
      最近更新 更多