简体   繁体   English

连接两个以asyncio.subprocess.create_subprocess_exec()开头的进程

[英]Connect two processes started with asyncio.subprocess.create_subprocess_exec()

When starting two processes with the old school subprocess.Popen() API, I can easily connect standard out of one process to standard in of another process, creating a pipeline in the same way as a UNIX shell will do when connecting commands with | 当与老同学开始两个过程subprocess.Popen() API,我可以轻松连接标准出一个进程的标准在另一个进程中,创造了以同样的方式作为管道在UNIX外壳连接与命令时会做| :

from subprocess import Popen, PIPE

process_1 = Popen(['ls'], stdout = PIPE)
process_2 = Popen(['wc'], stdin = process_1.stdout)

process_1.wait()
process_2.wait()

How can I accomplish the same when using the asynchronous API from asyncio.subprocess.create_subprocess_exec() (or similar)? asyncio.subprocess.create_subprocess_exec()使用异步API时,如何完成相同的工作? This is what I tried: 这是我尝试的:

from asyncio.events import get_event_loop
from asyncio.subprocess import PIPE, create_subprocess_exec

async def main():
    process_1 = await create_subprocess_exec('ls', stdout = PIPE)
    process_2 = await create_subprocess_exec('wc', stdin = process_1.stdout)

    await process_1.wait()
    await process_2.wait()

get_event_loop().run_until_complete(main())

But the second call to create_subprocess_exec() complains that the argument passed to stdin has no fileno (which is true): 但是对create_subprocess_exec()的第二次调用抱怨传递给stdin的参数没有fileno (这是真的):

Traceback (most recent call last):
  File ".../test-async.py", line 11, in <module>
     get_event_loop().run_until_complete(main())
[...]
  File ".../test-async.py", line 6, in main
     process_2 = await create_subprocess_exec('wc', stdin = process_1.stdout)
[...]
  File "/opt/local/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/subprocess.py", line 1388, in _get_handles
     p2cread = stdin.fileno()
AttributeError: 'StreamReader' object has no attribute 'fileno'

How can I get the same result as in the synchronous example above? 如何获得与上述同步示例相同的结果?

In asyncio, process.stdout is actually a StreamReader , not a file object. 在asyncio中, process.stdout实际上是StreamReader ,而不是文件对象。 The file object can be accessed through process._transport._proc.stdout . 可以通过process._transport._proc.stdout访问文件对象。 Unfortunately, you won't be able to use it since it has already been registered in the event loop in order to provide the stream interface process.stdout . 不幸的是,您将无法使用它,因为它已经在事件循环中注册,以便提供流接口process.stdout

One way to deal with the issue is to create your own pipe and pass the file descriptors to the subprocess: 解决该问题的一种方法是创建自己的管道并将文件描述符传递给子进程:

async def main():
    read, write = os.pipe()
    process_1 = await create_subprocess_exec('ls', stdout=write)
    os.close(write)
    process_2 = await create_subprocess_exec('wc', stdin=read, stdout=PIPE)
    os.close(read)
    return await process_2.stdout.read()

Note that the write file descriptor should be explicitly closed once the first subprocess is started (it is not automatically closed unless you use subprocess.PIPE ). 请注意,一旦启动第一个子流程,就应显式关闭write文件描述符(除非您使用subprocess.PIPE否则它不会自动关闭)。 The read file descriptor also needs to be closed, as explained here . read文件描述符也需要被关闭,如解释在这里

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM