将数据从子进程传递到父进程,管道在Windows上不工作

2024-06-30 15:33:45 发布

您现在位置:Python中文网/ 问答频道 /正文

目标是在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是否可继承无关。在Python3.2(默认情况下FD仍然是可继承的)上,它以同样的方式失败。还有什么原因造成这种差异?(EDIT:原因是,从Python3.2开始,2以上的FDs在默认情况下是关闭的。通过传递close_fds=False可以解决这个问题)

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

在所有平台上,在Python2和Python3上,从子级向父级传递数据(几个字节)的健壮而干净的方法是什么


Tags: 数据inimportchild字节oschecksys
2条回答

我想你要找的是一个多处理队列

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

编辑

“这是如何解决问题的?”

您正试图在子进程中执行代码,您需要一种将数据获取到父进程的方法。如果查看文档,您将看到如下代码片段:

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更改为有意义的名称。将该函数放在不同的文件中并导入它,然后使其执行

the ^{} documentation

If close_fds is true, all file descriptors except 0, 1 and 2 will be closed before the child process is executed. Otherwise when close_fds is false, file descriptors obey their inheritable flag as described in Inheritance of File Descriptors.

pass_fds is an optional sequence of file descriptors to keep open between the parent and child.

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

相关问题 更多 >