【发布时间】:2018-12-21 10:21:53
【问题描述】:
当我必须在异步事件循环中运行子进程时,子进程通信挂起,而整个事情都在一个单独的线程中。
我了解到为了在单独的线程中运行子进程,我需要有
1. an event loop running in main thread, and
2. a child watcher must be initiated in main thread.
在具备上述条件后,我得到了我的子流程工作。但是 subprocess.communicate 现在挂了。如果从主线程调用它,相同的代码正在工作。
进一步挖掘后,我观察到通信挂起,因为该过程没有自行完成。 ie await process.wait() 居然挂了。
当我尝试在子进程本身发出的命令挂起时,我看到通信挂起,但这里不是这种情况。
import asyncio
import shlex
import threading
import subprocess
async def sendcmd(cmd):
cmdseq = tuple(shlex.split(cmd))
print(cmd)
p = await asyncio.create_subprocess_exec(*cmdseq, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print(p.pid)
output = (await asyncio.wait_for(p.communicate(), 5))[0]
output = output.decode('utf8')
print(output)
return output
async def myfunc(cmd):
o = await sendcmd(cmd)
return o
def myfunc2():
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
tasks = []
tasks.append(asyncio.ensure_future(myfunc('uname -a')))
loop.run_until_complete(asyncio.gather(*tasks))
async def myfunc3():
t = threading.Thread(target=myfunc2)
t.start()
t.join()
def main():
asyncio.get_child_watcher()
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.ensure_future(myfunc3()))
loop.close()
main()
【问题讨论】:
-
为什么要结合线程和异步?您是否考虑过以不需要线程的方式构建程序?如果你有阻塞代码要运行,你可以随时使用
run_in_executor。 -
我考虑过重组,但工作量很大。事实上,除了完成这项工作之外,我还很好奇是什么让行为有所不同。
-
为了更清楚地说明我的要求——我有一个调度程序守护程序,它在套接字服务器(线程)上进行侦听,当收到请求时它会执行一些工作。当在线程套接字服务器上收到请求时触发此作业时,将在线程上,并且该作业包含异步事件循环。
-
我考虑过用异步套接字服务器代替线程套接字服务器(尽管此时这对我来说是一项艰巨的任务)。通过这样做,由于套接字服务器的事件循环已经在运行,因此它不会允许该作业所需的另一个事件循环。
-
@user4815162342 run_in_executor 与 p.communicate() 有同样的问题,它在不在主线程中执行时挂起!
标签: python subprocess python-asyncio