使用gevent和stdin管理子进程

时间:2017-05-09 03:29:33

标签: python gevent

我编写了一个小程序来启动和停止从stdin读取命令的子进程,使用gevent,希望有效地等待命令输入和进程完成。

它有一个命令R - 运行,它将stdin读作一行。

R只需使用脚本sleep 2; echo "Hello, world!"启动,如果它尚未运行

有两个greenlet,一个读取命令输入,一个等待新进程或等待当前进程完成。我使用gevent Event在两者之间切换。

我的问题:该过程的greenlet永远不会允许完成。命令greenlet似乎始终在运行,并且永远不会放弃控制。为什么进程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中恢复。

1 个答案:

答案 0 :(得分:0)

我对自己的问题有两个解决方案。这些中的任何一个都会使我的示例程序按预期运行。

标准输入管道

使用Popen(..., stdin=PIPE)打开子流程。如果没有它,gevent将无法工作,因为它必须等待某事

使用FileObjectThread

无论子进程是如何创建的,这似乎都有效,不知道为什么