持久的python子进程

时间:2012-01-23 23:20:56

标签: python subprocess

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

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

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

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

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

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)

我可以让这个过程开放,我真的很感激。

4 个答案:

答案 0 :(得分:25)

您可以使用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

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

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

在此示例中,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 是您需要编写的函数,如果您到目前为止收到的数据是您希望得到的所有输出,则返回validate_output()

答案 1 :(得分:5)

communicate()的调用正在杀死你的子进程。根据{{​​3}},communicate()方法将:

  

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

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

  

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

因此,您需要为潜在的死锁实施自己的变通方法,或者希望有人为您编写subprocess documentation

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

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

当我运行它时,会打印:

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 

答案 2 :(得分:1)

我认为你正在寻找

myprocess.stdin.write(text)

你可以创建一个Popens列表,然后在另一个循环中的每个元素上调用communication。 像这样的东西

processes=[]
for text in textcollection:
    myprocess = subprocess.Popen(["myexecutable"],
                stdin = subprocess.PIPE, stdout = subprocess.PIPE,
                stderr = None)
    myprocess.stdin.write(text)
    processes.append(myprocess)

for proc in processes:
    myoutput, err=proc.communicate()
    #do something with the output here

这样就不必等到所有Popens开始之后

答案 3 :(得分:-2)

if os.name == 'nt':
 startupinfo = subprocess.STARTUPINFO()
 startupinfo.dwFlags |= subprocess._subprocess.STARTF_USESHOWWINDOW
 subprocess.call(os.popen(tempFileName), shell=True)
 os.remove(tempFileName)