首页 文章

来自子进程标准输出的可靠非阻塞读取

提问于
浏览
3

注意:我有一个进程将一行写入stdout(“print(”hello“))并等待raw_input . 我使用p = subprocess.Popen运行此进程,然后调用p.stdout.readline()....这无限期地阻塞 . 我设置shell = False ...为什么我不能读取第一个输出?

p = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin = subprocess.PIPE)
    print(p.stdout.readline())

我已经看到this线程关于非阻塞io的子进程 . 我正在尝试创建一个读取和写入进程的交互式子进程对象 . 我发现stdout正在阻塞,即使有输出发送到stdout . 为了测试这个,我编写了一个程序,它将整数增加到stdout并通过子进程调用它 . 然后我使用涉及队列的非阻塞方法来读取stdout . 我发现,尽管这个过程每秒将1000行吐出到stdout,但是Stdout一次阻塞很长一段时间,完全随机地返回一条线...每千个中有一个,然后是每10个中有一个等等 . 为什么会发生这种情况的想法?如果我减慢打印机每0.5秒打印一次,我从来没有从stdout读取 . 就像它在响应单行之前需要1000次写入sdtout一样 .

注意:我进入睡眠状态,因此在启动侦听线程和从中读取之间有一段时间 . 现在,我总是从stdout返回,但我得到一个随机的单行 . 我想我不懂stdout . 它不缓冲吗?我的意思是,我想通过我的进程获取所有吐出的内容,但似乎它只保存了最后一行 . 我找不到关于这些PIPE事情的文档 .

def getStdOut(self):
        '''
            reads standard out
        '''
        return self.nonBlockingRead()


    def enqueue_output(self, out, queue, kill):
        line = ""
        kill = True
        while kill:
            line = out.readline()
            queue.put(line)

#             for line in iter(out.readline, b''):
#                 queue.put(line)
#             out.close()

    def nonBlockingRead(self):
        '''
             taken from the internet
        '''
        import sys
        from subprocess import PIPE, Popen
        from threading  import Thread
        sleep(0.5) #I inserted this later
        try:
            from Queue import Queue, Empty
        except ImportError:
            from queue import Queue, Empty  # python 3.x

        ON_POSIX = 'posix' in sys.builtin_module_names

        killThread = False                
        self.q = Queue()
        t = Thread(target=self.enqueue_output, args=(self.theProcess.stdout, self.q, killThread))
        t.daemon = True # thread dies with the program
        t.start()

        line = ''
        try:  
            line = self.q.get_nowait() # or q.get(timeout=.1)
        except Exception as e:
            print(e)
            print('no output yet')
        killThread = True
        return line




if __name__ == "__main__" :
    '''
        unit tests
    '''
    import time
    cmd = 'python "C:\InteractiveTest.py"'
    aSubProc = subProcessWStdIn(cmd, 10)
    while True :    
#        print(aSubProc.writeToProcess('y'))
        print(aSubProc.getStdOut())

1 回答

  • 0

    readline 从类文件对象 PIPE 中读取一行,将其全部读取,只需将其包装在while循环中即可 . 每次读取后还应调用 sleep 以节省CPU周期 .

    这是一个简单的例子:

    import subprocess
    
    p = subprocess.Popen(
        ['ls', '-lat'],
        shell=False,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        stdin=subprocess.PIPE
    )
    while True:
        line = p.stdout.readline()
        if line == '':
            break
        print(line.strip())  # remove extra ws between lines
    

    编辑:

    哇,对不起,我完全错过了你试图在其他过程中阅读输入的部分......

    所以,对于你的其他过程,看起来像:

    print('Hello')
    in = raw_input()
    

    然后,打印实际上将内容发送到您之前传递的文件类对象 PIPE ,该对象具有自己的缓冲机制 . print() function docs中解释了此行为

    要解决此问题,只需在 print 和_2981103之间添加 sys.stdout.flush()

    print('Hello')
    sys.stdout.flush()  # "flush" the output to our PIPE
    in = raw_input()
    

相关问题