持久的python子进程

Jas*_*ond 10 python subprocess

有没有办法在python"持久"中进行子进程调用?我正在调用一个需要一段时间来加载多次的程序.因此,如果我可以让该程序保持打开并与之通信而不会将其删除,那将会很棒.

我的python脚本的卡通版本如下所示:

for text in textcollection:
    myprocess = subprocess.Popen(["myexecutable"],
                stdin = subprocess.PIPE, stdout = subprocess.PIPE,
                stderr = None)
    myoutputtext, err = myprocess.communicate(input=text)
Run Code Online (Sandbox Code Playgroud)

我需要单独处理每个文本,因此将它们全部加入一个大文本文件并处理一次不是一个选项.

最好是,如果有这样的选项

myprocess = subprocess.Popen(["myexecutable"],
            stdin = subprocess.PIPE, stdout = subprocess.PIPE,
            stderr = None)    for text in textcollection:
for text in textcollection:
    myoutputtext, err = myprocess.communicate(input=text)
Run Code Online (Sandbox Code Playgroud)

我可以把这个过程打开,我真的很感激.

And*_*ark 26

您可以使用myprocess.stdin.write()myprocess.stdout.read()与子进程通信,您只需要小心确保正确处理缓冲以防止阻止您的呼叫.

如果您的子进程的输出是明确定义的,您应该能够使用行缓冲和可靠地与它进行通信myprocess.stdout.readline().

这是一个例子:

>>> p = subprocess.Popen(['cat'], bufsize=1, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
>>> p.stdin.write('hello world\n')
>>> p.stdout.readline()
'hello world\n'
>>> p.stdout.readline()        # THIS CALL WILL BLOCK
Run Code Online (Sandbox Code Playgroud)

Unix的这种方法的替代方法是将文件句柄置于非阻塞模式,这将允许您调用函数myprocess.stdout.read(),并使其返回数据(如果有),或者IOError如果没有任何数据则引发:

>>> p = subprocess.Popen(['cat'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
>>> import fcntl, os
>>> fcntl.fcntl(p.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
0
>>> p.stdout.read()         # raises an exception instead of blocking
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IOError: [Errno 11] Resource temporarily unavailable
Run Code Online (Sandbox Code Playgroud)

这可以让你做这样的事情:

fcntl.fcntl(p.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
for text in textcollection:
    myprocess.stdin.write(text + '\n')
    while True:
        myoutputtext = ''
        try:
            myoutputtext += myprocess.stdout.read()
        except IOError:
            pass
        if validate_output(myoutputtext):
            break
        time.sleep(.1)    # short sleep before attempting another read
Run Code Online (Sandbox Code Playgroud)

在这个例子中,如果您到目前为止收到的数据是您希望得到的所有输出,那么validate_output()您需要编写的函数将返回True.


srg*_*erg 5

调用communicate()就是杀死你的子进程.根据子流程文档,communicate()方法将:

与流程交互:将数据发送到stdin.从stdout和stderr读取数据,直到达到文件结尾.等待进程终止.

您想要做的是直接与POpen对象stdinstdout属性交互以与子进程通信.但是,文档建议不要这样说:

警告:使用communic()而不是.stdin.write,.stdout.read或.stderr.read来避免由于任何其他OS管道缓冲区填满和阻止子进程而导致的死锁.

因此,您需要为潜在的死锁实现自己的变通方法,或者希望有人为您编写了异步子流程模块.

编辑:这是一个如何使用异步子进程模块的快速例子:

import asyncsubprocess

textcollection = ['to', 'be', 'or', 'not', 'to be', 'that is the', 'question']

myprocess = asyncsubprocess.Popen(["cat"],
     stdin = asyncsubprocess.PIPE,
     stdout = asyncsubprocess.PIPE,
     stderr = None)

for text in textcollection:
    bytes_sent, myoutput, err = myprocess.listen(text)
    print text, bytes_sent, myoutput, err
Run Code Online (Sandbox Code Playgroud)

当我运行它时,它打印:

to 2 to 
be 2 be 
or 2 or 
not 3 not 
to be 5 to be 
that is the 11 that is the 
question 8 question 
Run Code Online (Sandbox Code Playgroud)