【问题标题】:Pass data from child process to parent process, pipe doesn’t work on Windows将数据从子进程传递到父进程,管道在 Windows 上不起作用
【发布时间】:2020-07-08 01:48:23
【问题描述】:

目标是在 Python 中将一些数据(几个字节)从子进程传递到父进程(不能使用 stdout 和 stderr)。下面是它的简化版本(实际代码在阻塞子进程之前从管道中读取所有数据)。

import os
import subprocess
import sys

CHILD_SCRIPT = r'''
import os
os.write({wfd}, b'Hello, World!')
'''

rfd, wfd = os.pipe()
if hasattr(os, 'set_inheritable'):
    os.set_inheritable(wfd, True)
subprocess.check_call([sys.executable, '-c', CHILD_SCRIPT.format(wfd=wfd)])
print(os.read(rfd, 1024))

在 Unix 上,它适用于 Python 2,但不适用于 Python 3,它会失败并显示:

Traceback (most recent call last):
  File "<string>", line 3, in <module>
OSError: [Errno 9] Bad file descriptor
Traceback (most recent call last):
  File "test_inherit_fd.py", line 13, in <module>
    subprocess.check_call([sys.executable, '-c', CHILD_SCRIPT.format(wfd=wfd)])
  File "/usr/lib/python3.8/subprocess.py", line 364, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['/bin/python3', '-c', "\nimport os\nos.write(5, b'Hello, World!')\n"]' returned non-zero exit status 1.

显然,失败与FD是否可继承无关。在 Python 3.2(默认情况下 FD 仍可继承)上,它以同样的方式失败。还有什么导致差异的? (编辑:原因是,从 Python 3.2 开始,默认关闭 2 以上的 FD。通过close_fds=False 可以解决问题。

在 Windows 上,它在 Python 2 和 Python 3 上失败。

在所有平台上的 Python 2 和 Python 3 上,将数据(几个字节)从子级传递到父级的稳健且干净的方式是什么?

【问题讨论】:

    标签: python subprocess file-descriptor


    【解决方案1】:

    来自the subprocess documentation

    如果 close_fds 为真,则除012 之外的所有文件描述符都将在子进程执行之前关闭。否则,当 close_fds 为 false 时,文件描述符遵循 Inheritance of File Descriptors 中所述的可继承标志。

    pass_fds 是一个可选的文件描述符序列,用于在父子节点之间保持打开状态。

    要使其工作,请将close_fds=Falsepass_fds=[wfd] 作为参数添加到subprocess.check_call。快速测试表明,如果您使用pass_fds,那么您将不再需要调用set_inheritable,但如果您使用close_fds,则情况并非如此。

    【讨论】:

      【解决方案2】:

      我认为您正在寻找的是一个 multiprocessing.Queue。

      Python 3:https://docs.python.org/3/library/multiprocessing.html#exchanging-objects-between-processes

      Python 2:https://docs.python.org/2/library/multiprocessing.html#exchanging-objects-between-processes

      您也可以使用管道(来自同一个库),但它比队列慢很多:Python 3.4 multiprocessing Queue faster than Pipe, unexpected

      编辑

      “这如何解决这个问题?”

      您正在尝试在子进程中执行代码,并且您需要一种将数据获取到父进程的方法。如果你去看文档,你会看到这样的代码 sn-p:

      from multiprocessing import Process, Queue
      
      def f(q):
          q.put([42, None, 'hello'])
      
      if __name__ == '__main__':
          q = Queue()
          p = Process(target=f, args=(q,))
          p.start()
          print(q.get())    # prints "[42, None, 'hello']"
          p.join()
      

      在这种情况下,f 是将由子进程执行的代码。你可以在那里做任何你想做的事!做一个1000行的函数。创建一个类,实例化它然后发疯。将名称从 f 更改为有意义的名称。将该函数放在不同的文件中并导入它,然后执行它。

      【讨论】:

        猜你喜欢
        • 2016-03-31
        • 1970-01-01
        • 1970-01-01
        • 2013-06-19
        • 1970-01-01
        • 1970-01-01
        • 2014-03-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多