缓冲进程输出导致截断?

2024-04-16 05:58:00 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个包含100行的示例文件,我正在使用带有cat的子进程读取该文件。但是,队列中的输出总是被截断的。我怀疑这可能是由于cat缓冲其输出,因为它检测到一个管道。在

p = subprocess.Popen("cat file.txt",
                     stdout=subprocess.PIPE,
                     stderr=subprocess.PIPE,
                     stdin=subprocess.PIPE,
                     shell=True,
                     bufsize=0)

我使用不同的线程从cat的stdout和stderr管道读取:

^{pr2}$

启动这些线程并将它们读取的内容转储到队列中。当cat处于活动状态时,主线程从该队列读取数据。在

with CancelFunction(p.kill):
    try:
      stdout_thread = threading.Thread(target=StdOutThread)
      stdout_thread.start()
      while p.poll() is None:
        ReadFromQueue()
      while not queue.empty():
        ReadFromQueue()  
    finally:
      running = False
      stdout_thread.join()

我已经考虑过使用pexpect来克服这个问题,但同时也希望区分stdout和stderr,这在pexpect中似乎是不可能的。我们将不胜感激。在


Tags: 文件示例管道队列进程stderrstdout线程
1条回答
网友
1楼 · 发布于 2024-04-16 05:58:00

我确信在读取cat的所有输出并将其放入队列之前,主线程正在退出try块。在

请注意,cat可以退出,即使您尚未读取其所有输出。 考虑以下事件序列:

  1. cat写出最后一行
  2. cat退出
  3. 在读线程进行更改以从cat读取最后一位输出之前,主线程检测到cat已退出(通过p.poll()
  4. 然后,主线程退出try块并将running设置为false
  5. 读取器线程退出,因为running为false,但在此之前 已读取最后一个输入。在

下面是在队列中使用sentinel值的简单方法 通知主线程一个读线程已经退出。在

如果cat退出,那么它最终将到达它所在的管道上的EOF 监控。当这种情况发生时,它不会把任何人放在队列中 通知主线程它完成了。当两个读线程 完成主线程可以安全地停止监视队列和 把线连接起来。在

import threading
import subprocess
import os
import time
import Queue
import sys

def pipe_thread(queue, name, handle):
  print "in handlehandle"
  for line in handle:
    if line[-1] == "\n":
      line = line[:-1]
    queue.put( (name, line) )
  queue.put(None)

def main():
    p = subprocess.Popen("cat file.txt",
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE,
                         stdin=subprocess.PIPE,
                         shell=True,
                         bufsize=0)

    queue = Queue.Queue()

    t1 = threading.Thread(target = pipe_thread,
                             args = [queue, "stdout", p.stdout])
    t2 = threading.Thread(target = pipe_thread,
                             args = [queue, "stderr", p.stderr])

    t1.start()
    t2.start()

    alive = 2
    count = 0
    while alive > 0:
      item = queue.get()
      if item == None:
        alive = alive - 1
      else:
        (which, line) = item
        count += 1
        print count, "got from", which, ":", line
    print "joining..."
    t1.join()
    t2.join()

main()

相关问题 更多 >