2015-04-22 54 views
2

我有一个名为BOB.exe的可执行函数,它只用短暂的暂停将标准量的文本输出到stdout。 BOB也有冻结的习惯,所以我编写了一个python监视器函数,它使用子进程模块调用BOB可执行文件,将其指向临时文件并监视临时文件的大小以查看它是否已崩溃。这是我目前的解决方案:Python:读取子进程的stdout而不打印到文件

#!/usr/bin/python 
from subprocess import Popen 
import tempfile, time 
def runBOB(argsList): 

    # Create a temporary file where BOB stdout will be piped 
    BOBout = tempfile.NamedTemporaryFile() 
    BOBoutSize = 0 

    # Start the subprocess of BOB 
    BOBsp = Popen(argsList, stdout=BOBout) 

    while True: 
     # See if subprocess has finished 
     if BOBsp.poll() is not None: 
      BOBout.close() # Destroy the temp file 
      return 0 

     # if the size of the stdout file has increased, BOB.exe is still running 
     BOBoutSizeNew = os.path.getsize(BOBout.name) 
     if BOBoutSizeNew > BOBoutSize: 
      BOBoutSize = BOBoutSizeNew 
     else: # if not, kill it 
      BOBsp.kill() 
      BOBout.close() # Destroy the temp file 
      return 1 

     # Check every 10 seconds 
     time.sleep(10) 

但是,这是非常慢,我认为写入文件是原因。有没有更高效的方法来做到这一点,比如观看标准输出流,然后立即将其发送给Null?任何减少打印兆字节数的内容都可能会有所帮助。是否有另一种方法来查看exe是否崩溃?我应该注意到,我不在乎stdout,反正这一切都将被忽略

谢谢你的帮助!

回答

2

您可以使用stdout=subprocess.PIPE来告诉subprocess,让您能够读取子进程的输出而不将其存储到文件中。棘手的部分是异步执行,以免在BOB.exe冻结时出现死锁。一个简单的方法是使用助手线程;尽管Python在线程中的声誉很差,但实际上这对于GIL不妨碍其中的线程来说是一个很好的用例。

只需创建一个帮助程序线程,除了读取与Bob输出相对应的文件句柄的输出外什么也不做。辅助线程立即丢弃输出并增加一个字节计数器。主线程实现与以前完全相同的逻辑,但使用内存计数器而不是重新检查文件大小。当Bob完成或被主线程终止时,辅助线程将接收EOF并退出。

这是一个未经考验的实现上面的:

#!/usr/bin/python 
import subprocess 
import threading 
import time 
import os 

bytes_read = 0 

def readBOB(pipe): 
    global bytes_read 
    bytes_read = 0 
    while True: 
     # Wait for some data to arrive. This must use os.read rather 
     # than pipe.read(1024) because file.read would block us if less 
     # than 1024 bytes of data arrives. (Reading one byte at a time 
     # with pipe.read(1) would work, but would be too slow at 
     # consuming large amounts of data.) 
     s = os.read(pipe.fileno(), 1024) 
     if not s: 
      return # EOF 
     # we are the only writer, so GIL serves as the lock 
     bytes_read += len(s) 

def runBOB(argsList): 
    # Start the subprocess of BOB 
    BOBsp = subprocess.Popen(argsList, stdout=subprocess.PIPE) 

    thr = threading.Thread(target=readBOB, args=(BOBsp.stdout,)) 
    thr.start() 
    old_bytes_read = -1 

    while True: 
     # See if subprocess has finished 
     if BOBsp.poll() is not None: 
      return 0 

     # if the size of the stdout has increased, BOB.exe is still running 
     new_bytes_read = bytes_read 

     if new_bytes_read > old_bytes_read: 
      old_bytes_read = new_bytes_read 
     else: # if not, kill it (readBOB will exit automatically) 
      BOBsp.kill() 
      return 1 

     # Check every 10 seconds 
     time.sleep(10) 
+0

非常感谢您为!也很容易理解。一个问题,因为我不太熟悉pythons线程:'readBOB'会在后台不断处理,或者循环运行的频率有一定限制吗?出于效率的原因,这是明智的吗? – FHTMitchell

+0

@Goose'readBOB'不是忙碌循环,如果这就是你所担心的。当没有数据要读时,'os.read'将会被阻塞,所以'readBOB'只会花费尽可能多的CPU来读取(和丢弃)Bob产生的1k块数据,这应该是可以忽略的。 – user4815162342

相关问题