使用 gevent 和 stdin 管理子进程
Managing a subprocess with gevent and stdin
我编写了一个小程序来根据从标准输入读取的命令启动和停止子进程,希望使用 gevent 有效地等待命令输入和进程完成。
它有一个命令 R
- 运行,它将标准输入读取为一行。
R
如果它还没有 运行ning
,只需使用脚本 sleep 2; echo "Hello, world!"
启动 sh
有两个greenlet,一个读取命令输入,一个等待新进程或等待当前进程完成。我使用 gevent Event
在两者之间切换。
我的问题:进程的 greenlet 永远不允许完成。命令 greenlet 似乎总是 运行ning 并且从不放弃控制。为什么进程 greenlet 永远不会从等待中醒来,即使进程明显已完成?
来源如下:
import sys
from gevent import spawn, joinall, sleep
from gevent.subprocess import Popen
from gevent.fileobject import FileObjectPosix
from gevent.event import Event
process = None
trigger = Event()
def start_process():
global process
process = Popen(['/bin/sh', '-c', 'sleep 2; echo Hello, World!'])
def wait_process():
global process
while True:
trigger.wait()
print('INFO - Awaiting new process')
trigger.clear()
process.wait()
process = None
print('INFO - Process done')
def get_input():
global process
stdin_wrapped = FileObjectPosix(sys.stdin)
while True:
line = stdin_wrapped.readline().decode().strip()
if line == 'R':
if not process:
start_process()
trigger.set()
print('OK - Running process')
else:
print('FAIL - Process already running')
sleep(0)
def main():
joinall([
spawn(get_input),
spawn(wait_process)
])
if __name__ == '__main__':
main()
会话看起来像这样,R
s 之间有 >2s 的间隔:
R
OK - Running process
INFO - Awaiting new process
Hello, World!
R
FAIL - Process already running
我希望看到:
R
OK - Running process
INFO - Awaiting new process
Hello, World!
INFO - Process done
R
OK - Running process
我最初的想法是两个错误之一:
- 这不是使用 gevent 读取文件的正确方法
- 子进程等待事件没有被正确使用,它永远不会被唤醒。我还没有看到像这样使用它的示例,但是 Popen 对象可以与
gevent.wait
一起使用,所以我认为这是可以的。
- 如果我破坏调试器,堆栈跟踪显示它正在等待从 stdin 读取完成,我预计它会有一些
select
类似的行为,当两个 greenlet 正在等待某事时它会执行将在先完成的 greenlet 中恢复。
对于我自己的问题,我有两种解决方案。这些中的任何一个都会使我的示例程序按预期运行。
标准输入管道
用 Popen(..., stdin=PIPE)
打开子流程。没有它 gevent 将无法工作是有道理的,因为它必须等待 something.
使用FileObjectThread
无论子流程如何创建,这似乎都有效,不确定为什么
我编写了一个小程序来根据从标准输入读取的命令启动和停止子进程,希望使用 gevent 有效地等待命令输入和进程完成。
它有一个命令 R
- 运行,它将标准输入读取为一行。
R
如果它还没有 运行ning
sleep 2; echo "Hello, world!"
启动 sh
有两个greenlet,一个读取命令输入,一个等待新进程或等待当前进程完成。我使用 gevent Event
在两者之间切换。
我的问题:进程的 greenlet 永远不允许完成。命令 greenlet 似乎总是 运行ning 并且从不放弃控制。为什么进程 greenlet 永远不会从等待中醒来,即使进程明显已完成?
来源如下:
import sys
from gevent import spawn, joinall, sleep
from gevent.subprocess import Popen
from gevent.fileobject import FileObjectPosix
from gevent.event import Event
process = None
trigger = Event()
def start_process():
global process
process = Popen(['/bin/sh', '-c', 'sleep 2; echo Hello, World!'])
def wait_process():
global process
while True:
trigger.wait()
print('INFO - Awaiting new process')
trigger.clear()
process.wait()
process = None
print('INFO - Process done')
def get_input():
global process
stdin_wrapped = FileObjectPosix(sys.stdin)
while True:
line = stdin_wrapped.readline().decode().strip()
if line == 'R':
if not process:
start_process()
trigger.set()
print('OK - Running process')
else:
print('FAIL - Process already running')
sleep(0)
def main():
joinall([
spawn(get_input),
spawn(wait_process)
])
if __name__ == '__main__':
main()
会话看起来像这样,R
s 之间有 >2s 的间隔:
R
OK - Running process
INFO - Awaiting new process
Hello, World!
R
FAIL - Process already running
我希望看到:
R
OK - Running process
INFO - Awaiting new process
Hello, World!
INFO - Process done
R
OK - Running process
我最初的想法是两个错误之一:
- 这不是使用 gevent 读取文件的正确方法
- 子进程等待事件没有被正确使用,它永远不会被唤醒。我还没有看到像这样使用它的示例,但是 Popen 对象可以与
gevent.wait
一起使用,所以我认为这是可以的。 - 如果我破坏调试器,堆栈跟踪显示它正在等待从 stdin 读取完成,我预计它会有一些
select
类似的行为,当两个 greenlet 正在等待某事时它会执行将在先完成的 greenlet 中恢复。
对于我自己的问题,我有两种解决方案。这些中的任何一个都会使我的示例程序按预期运行。
标准输入管道
用 Popen(..., stdin=PIPE)
打开子流程。没有它 gevent 将无法工作是有道理的,因为它必须等待 something.
使用FileObjectThread
无论子流程如何创建,这似乎都有效,不确定为什么