2015-04-07 380 views
1

上周我发布了类似的question,这篇文章反映了我的试验和我现在面临的问题。Python - 如何在subprocess.Popen中从PIPE读取非阻塞?

通过Popen调用的程序是一个命令行程序。我使用一个线程从队列中读取一个项目并将其发送到stdin,并从stdout获取响应。但它proc.stdout.read()中挂起。我确实看到它在上周五的预期输出中正常工作,然后当我今天做了一些更改时,它会挂起。我所做的更改将使用readlines()取代read()并使用循环来迭代结果。我知道readlines()可能会阻止,但是当我将代码翻转到上周五的read()时,它也会阻止。我现在完全迷失了。任何可能的原因?

下面是代码从队列中取得一个句子,其提供给Java程序得到回应:

''' below is the code for worker thread. ''' 
def readQueue(proc, queue): 
    print 'enter queueThread.\n' 
    global notEmpty 
    notEmpty = True 
    while notEmpty: 
     try: 
      sen = queue.get() 
      proc.stdin.write(sen.strip()) 
      res = proc.stdout.read() 
      print res.strip(), ' ', sen 
      queue.task_done() 
     except Empty: 
      break 
    print 'leave queueThread.' 

下面的主线是从文件中读取每一行,并把它放在一个队列中的工作线程逐项处理:

def testSubprocess(): 
    ee = open('sentences.txt', 'r') 
    #ff = open('result.txt', 'w') # print it to stdout first before really write to a file. 
    lines = ee.readlines() 
    cmd = ['java', 
      '-cp', 'someUsefulTools.jar', 
      'className', 
      '-stdin',] # take input from stdin 
    proc = Popen(cmd, stdout=PIPE, stdin=PIPE, stderr=PIPE, bufsize=-1, universal_newlines=True) 
    q = Queue() 
    for sen in lines: 
     q.put(sen.strip()) 
    readThread = Thread(target=readQueue, args=(proc, q)) 
    readThread.daemon = True 
    readThread.start() 
    print 'Main thread is waiting...\n' 
    q.join() 
    global notEmpty; notEmpty = False 
    print 'Done!' 
+1

道歉,如果我误解你的代码,这是不行的,但是我发现我可以堵塞这种方式停止管道。 (我没有很多python线程的经验)在定义“proc”之后,添加这个:“fcntl.fcntl(proc,fcntl.F_SETFL,os.O_NONBLOCK)”如果proc被定义为类型“pipe “这应该阻止它阻止。你可能需要导入fcntl。 – Aphire

+0

@Aphire不知道我是否正确,它似乎“fcntl”用于linux/unix环境,对吧? (我的工作环境是windows) –

+0

想象一下,你给java程序发送一个句子:你怎么知道什么时候停止读取响应:它是否总是* 10个字节或者它总是*单行还是你想要读直到EOF即,每个进程只能回答**单个**问题? – jfs

回答

1

来自子流程的管道是类似文件的对象。

对这些对象的方法read()将所有内容都读入内存,直到达到EOF为止,如果没有指定应该读取多少内容,请参阅文档:https://docs.python.org/2/library/stdtypes.html#file.read

如果您不想要这种行为,您必须设置想要阅读的尺寸。尝试将其设置为1个字节?

这同样适用于readlines(),请参阅文档:https://docs.python.org/2/library/stdtypes.html#file.readlines

+0

已尝试并设置要读取的大小。问题依然存在。几乎要放弃并转向[pexpect](https://pexpect.readthedocs.org/en/latest/)。 –

+0

某些程序在通过pexpect执行时可能会有不同的行为,因为程序可以检测它们是否在终端(TTY设备)中运行。不知道Java程序是否可以做到这一点。例如,如果我在我的系统上运行'ps aux','ps'检测到终端只有80个字符宽,并相应地缩短了行。如果我们将输出输出到文件中(如使用子流程),它将不知道终端的宽度,因此不会缩短行数。 –