Python 使用gevent和stdin管理子流程

Python 使用gevent和stdin管理子流程,python,gevent,Python,Gevent,我已经编写了一个小程序,通过从stdin读取命令来启动和停止子进程,希望使用gevent有效地等待命令输入和进程完成 它有一个命令R-run,它将stdin作为一行读取 R只是用脚本sleep 2启动sh;如果尚未运行,则回显“Hello,world!” 有两个greenlet,一个读取命令输入,另一个等待新进程或当前进程完成。我使用gevent事件在两者之间切换 我的问题是:这个过程的底线是永远不允许完成。greenlet命令似乎始终在运行,并且从不放弃控制。为什么greenlet的过程永远不

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

它有一个命令
R
-run,它将stdin作为一行读取

R
只是用脚本
sleep 2启动sh;如果尚未运行,则回显“Hello,world!”

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

我的问题是:这个过程的底线是永远不允许完成。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中恢复执行

    • 对于我自己的问题,我有两种解决方案。这两个选项中的任何一个都将使我的示例程序按预期运行

      标准管道 使用
      Popen(…,stdin=PIPE)
      打开子流程。如果没有它,gevent将无法工作,这是有道理的,因为它必须等待一些东西

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