从正在Python中编写的打开文件句柄中读取

时间:2011-03-29 02:18:28

标签: python io nonblocking

我知道这是流处理中的经典问题,但我不知道如何在Python中处理它。我有一个由活动进程写入的文件句柄。我希望逐行使用该文件句柄中的内容,但我不想死锁等待阅读。我将继续阅读,直到EOF或60秒的循环阅读,以先到者为准。关于如何做到这一点的建议将不胜感激。我对这个问题的伪代码描述如下。

proc = genprocess("command")
found_a = False
found_b = False
start = time.time()
while True:
    line = proc.readline()
    while line:
        if not found_a and grep(pattern_a, line):
            found_a = True
            print "Found A, now looking for B"
        elif not found_b and grep(pattern_b, line):
            found_b = True
            print "Found B, all done"
            break
    if time.time() - start > 60:
        break
    else:
        time.sleep(5)

proc.kill()

问题是这只会在每个间隔读取一行。相反,我希望循环内部尽可能多地迭代,但阻止等待将新内容写入文件。一旦读取尽可能多的内容,它应该睡眠5秒钟以允许更多内容累积。

2 个答案:

答案 0 :(得分:2)

如果您在Unix环境中运行,可以使用Python的select module等待文件句柄上的数据。此外,您可以使用Python的fcntl module将文件句柄更改为非阻塞模式,如this question中所述。

例如,假设您的proc变量是支持fileno()的常规文件句柄:

file_num = proc.fileno()
old_flags = fcntl.fcntl(file_num, fcntl.F_GETFL)
fcntl.fcntl(file_num, fcntl.F_SETFL, old_flags | os.O_NONBLOCK)

答案 1 :(得分:1)

链接到上面的fcntl示例是正常的(除了它将进程置于繁忙的循环轮询中),但我最终使用“select”来实现所需功能的更多或更少。

    started = False
    while True:
        if (time.time() - start > wait_for) or started:
            break
        (rlist, wlist, xlist) = select([proc.stdout], [], [], wait_interval)
        if len(rlist) > 0:
            line = rlist[0].readline() # read one line (this blocks until '\n' is read)
        else: # nothing available to read from proc.stdout
            print ".",
            sys.stdout.flush()
            time.sleep(1)
            continue
        if re.search("daemon started", line):
            started = True

    if not started:
        proc.kill() # don't leave the process running if it didn't start properly

如果这是用户可能CTRL-C的那种事情,那么将整个事物放在try / except块中并查找KeyboardInterrupt允许调用proc.kill()而不是让进程在背景