Чтение из дескриптора открытого файла, который записывается в Python - PullRequest
1 голос
/ 29 марта 2011

Я знаю, что это классическая проблема в потоковой обработке, но я не знаю, как справиться с этим в 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 ]

2 голосов
/ 29 марта 2011

Если вы работаете в среде Unix, вы можете использовать Python select module для ожидания данных в дескрипторе файла.Кроме того, вы можете использовать Python fcntl module , чтобы изменить дескриптор файла на неблокирующий режим, как описано в этот вопрос .

Например, предполагая, что ваш 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 голос
/ 30 марта 2011

Пример 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 / Кроме и поиск KeyboardInterrupt позволяет вызывать proc.kill () вместо того, чтобы оставить процесс запущенным в фон.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...