简体   繁体   English

使用gevent和stdin管理子流程

[英]Managing a subprocess with gevent and stdin

I have written a small program to start and stop a subprocess on command from read from stdin, using gevent to, hopefully, efficiently wait for both the command input, and for the process to finish. 我编写了一个小程序来启动和停止从stdin读取命令的子进程,使用gevent希望有效地等待命令输入和进程完成。

It has one command R - run, which it read of stdin as a line. 它有一个命令R -run,它将stdin读为一行。

R simply starts sh with the script sleep 2; echo "Hello, world!" R只是从脚本sleep 2; echo "Hello, world!"开始sh sleep 2; echo "Hello, world!" sleep 2; echo "Hello, world!" if it is not already running 如果尚未运行

There are two greenlets, one reading command input and one waiting for a new process or waiting for the current process to finish. 有两个Greenlet,一个为读取命令输入,另一个为等待新进程或等待当前进程完成。 I use an gevent Event to toggle between the two. 我使用gevent Event在两者之间切换。

My problem: The greenlet for the process is never allow to finish. 我的问题:该流程的准入门槛永远都无法完成。 The command greenlet appears to always be running and never relinquishes control. 命令greenlet似乎始终在运行,并且永不放弃控制权。 Why does the process greenlet never wake from its wait, even when the process is clearly finished? 为什么即使进程显然已经完成,进程greenlet也从不从等待中唤醒?

The source is as follows: 来源如下:

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()

A session looks like this, with a >2s gap between the R s: 会话看起来像这样, R s之间的间隔大于2s:

R
OK - Running process
INFO - Awaiting new process
Hello, World!
R
FAIL - Process already running

I expect to see: 我希望看到:

R
OK - Running process
INFO - Awaiting new process
Hello, World!
INFO - Process done
R
OK - Running process

My initial ideas are one of two things are going wrong: 我最初的想法是出了两件事之一:

  • This is not the correct way to read a file with gevent 这不是使用gevent读取文件的正确方法
  • the subprocess wait event is not being used correctly, and it never wakes up. 子进程等待事件未正确使用,并且从不唤醒。 I have not seen an example where it is used like this, but Popen objects can be used with gevent.wait so I assumed this was ok. 我还没有看到这样使用它的示例,但是Popen对象可以与gevent.wait一起使用,所以我认为这没问题。
  • If I break the debugger the stack trace shows that is is waiting for the read from stdin to finish, I expected it to have some select like behaviour, and when two greenlets were waiting on something it would execution would resume in the greenlet that finished first. 如果我中断调试器,则堆栈跟踪显示正在等待从stdin读取完成,我希望它具有某些select例如行为,当两个greenlet等待某事时,它将在首先完成的greenlet中恢复执行。

I have two solutions to my own problem. 对于我自己的问题,我有两种解决方案。 Either of these will make my example program function as expected. 这些都可以使我的示例程序按预期运行。

Pipe for stdin 标准管

Open the subprocess with Popen(..., stdin=PIPE) . 使用Popen(..., stdin=PIPE)打开子Popen(..., stdin=PIPE) It makes sense that gevent won't work without that since it must wait on something . 有意义的是,如果没有它,gevent就无法工作,因为它必须等待某些事情

Use FileObjectThread 使用FileObjectThread

This seems to work regardless of how the subprocess is created, not sure why 😐 不管子流程是如何创建的,这似乎都可行,不确定为什么

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

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