Python: select () не сигнализирует все входные данные из канала

Я пытаюсь загрузить внешнюю программу командной строки с помощью Python и связываться с ней через каналы. Программа принимает текстовый ввод через stdin и производит вывод текста в строках в stdout. Коммуникация должна быть асинхронной, используя select ().

Проблема в том, что не весь вывод программы сигнализируется в select (). Обычно одна или две строки не сигнализируются. Если select () возвращается с таймаутом, и я пытаюсь читать из канала, в любом случае readline () немедленно возвращает строку, отправленную из программы. См. Код ниже.

Программа не буферизует вывод и отправляет весь вывод в текстовые строки. Подключение к программе через каналы во многих других языках и средах пока прекратилось.

Я пробовал Python 3.1 и 3.2 на Mac OSX 10.6.

import subprocess import select engine = subprocess.Popen("Engine", bufsize=0, stdin=subprocess.PIPE, stdout=subprocess.PIPE) engine.stdin.write(b"go\n") engine.stdin.flush() while True: inputready,outputready,exceptready = select.select( [engine.stdout.fileno()] , [], [], 10.0) if (inputready, outputready, exceptready) == ([], [], []): print("trying to read from engine anyway...") line = engine.stdout.readline() print(line) for s in inputready: line = engine.stdout.readline() print(line) 

  • Python: кортежи / словари в качестве ключей, выберите, отсортируйте
  • Как проверить, находится ли значение в списке при выборе из кадра данных pandas?
  • select и ssl в python
  • Pandas DataFrame: удалить конкретную дату во все високосные годы
  • pyodbc - Как выполнить оператор select с использованием переменной для параметра
  • Использование подпроцесса с select и pty зависает при захвате вывода
  • WTForms: Как выбрать опции в SelectMultipleField?
  • Как запросить для всех групп типа 'foo', которые содержат user_x? (таблица «многие-ко-многим»)
  • One Solution collect form web for “Python: select () не сигнализирует все входные данные из канала”

    Обратите внимание, что внутренне file.readlines([size]) петли и вызывает многократный вызов read() один раз, пытаясь заполнить внутренний буфер size . Первый вызов read() будет немедленно возвращен, так как select () указал, что fd читается. Однако 2-й вызов блокируется до тех пор, пока не будут доступны данные, что приведет к победе над целью использования выбора. В любом случае сложно использовать file.readlines([size]) в асинхронном приложении.

    Вы должны вызывать os.read(fd, size) один раз на каждом fd для каждого прохода через select. Это выполняет неблокируемое чтение и позволяет вам частично или частично дублировать линии до тех пор, пока данные не будут доступны и не обнаружит EOF однозначно.

    Я изменил ваш код, чтобы проиллюстрировать использование os.read . Он также читает из процесса ' stderr :

     import os import select import subprocess from cStringIO import StringIO target = 'Engine' PIPE = subprocess.PIPE engine = subprocess.Popen(target, bufsize=0, stdin=PIPE, stdout=PIPE, stderr=PIPE) engine.stdin.write(b"go\n") engine.stdin.flush() class LineReader(object): def __init__(self, fd): self._fd = fd self._buf = '' def fileno(self): return self._fd def readlines(self): data = os.read(self._fd, 4096) if not data: # EOF return None self._buf += data if '\n' not in data: return [] tmp = self._buf.split('\n') lines, self._buf = tmp[:-1], tmp[-1] return lines proc_stdout = LineReader(engine.stdout.fileno()) proc_stderr = LineReader(engine.stderr.fileno()) readable = [proc_stdout, proc_stderr] while readable: ready = select.select(readable, [], [], 10.0)[0] if not ready: continue for stream in ready: lines = stream.readlines() if lines is None: # got EOF on this stream readable.remove(stream) continue for line in lines: print line 
    Interesting Posts
    Python - лучший язык программирования в мире.