Недавно я должен был читать I/O на stdin, stdout в python с кросс-платформенной совместимостью.
Для linux:
для linux мы можем использовать select модуль. Это реализация оболочки posix select
. Он позволяет передавать несколько файловых дескрипторов, дожидаясь их готовности. Как только они будут готовы, вы будете уведомлены, и может быть выполнено действие read/write
. Вот немного кода, который поможет вам идею
здесь nodejs является докер среда с nodejs изображением
stdin_buf = BytesIO(json.dumps(fn) + "\n")
stdout_buf = BytesIO()
stderr_buf = BytesIO()
rselect = [nodejs.stdout, nodejs.stderr] # type: List[BytesIO]
wselect = [nodejs.stdin] # type: List[BytesIO]
while (len(wselect) + len(rselect)) > 0:
rready, wready, _ = select.select(rselect, wselect, [])
try:
if nodejs.stdin in wready:
b = stdin_buf.read(select.PIPE_BUF)
if b:
os.write(nodejs.stdin.fileno(), b)
else:
wselect = []
for pipes in ((nodejs.stdout, stdout_buf), (nodejs.stderr, stderr_buf)):
if pipes[0] in rready:
b = os.read(pipes[0].fileno(), select.PIPE_BUF)
if b:
pipes[1].write(b)
else:
rselect.remove(pipes[0])
if stdout_buf.getvalue().endswith("\n"):
rselect = []
except OSError as e:
break
Для окон Этот пример кода имеет как операции чтения и записи с стандартного ввода, стандартный вывод вовлеченного. Теперь этот код не будет работать с ОС Windows, потому что при использовании окон выборка не позволяет stdin, stdout передаваться как аргументы.
Docs говорит:
Файловые объекты на Windows, не являются приемлемыми, но сокеты. В Windows основная функция select() предоставляется библиотекой WinSock и не обрабатывает дескрипторы файлов, которые не происходят из WinSock.
Во-первых, я должен сказать, что есть много библиотек для неблокирующая ввода-вывода для чтения/на окнах, как asyncio
(Python 3), gevent
(для Python 2.7), msvcrt
, а затем есть «s win32event
pywin32
что предупредите вас, если ваш сокет готов к read/write
данным.Но ни один из них не позволил мне читать писать на stdin/stdout
давая как иных ошибок
An operation is performend on something that is not a socket
Handles only expect integer values
и т.д.
Есть некоторые другие библиотеки twister
, что я не пробовал.
Теперь, чтобы реализовать такую функциональность, как в вышеупомянутом коде на платформе Windows, я использовал threads
. вот мой код:
stdin_buf = BytesIO(json.dumps(fn) + "\n")
stdout_buf = BytesIO()
stderr_buf = BytesIO()
rselect = [nodejs.stdout, nodejs.stderr] # type: List[BytesIO]
wselect = [nodejs.stdin] # type: List[BytesIO]
READ_BYTES_SIZE = 512
# creating queue for reading from a thread to queue
input_queue = Queue.Queue()
output_queue = Queue.Queue()
error_queue = Queue.Queue()
# To tell threads that output has ended and threads can safely exit
no_more_output = threading.Lock()
no_more_output.acquire()
no_more_error = threading.Lock()
no_more_error.acquire()
# put constructed command to input queue which then will be passed to nodejs's stdin
def put_input(input_queue):
while True:
sys.stdout.flush()
b = stdin_buf.read(READ_BYTES_SIZE)
if b:
input_queue.put(b)
else:
break
# get the output from nodejs's stdout and continue till otuput ends
def get_output(output_queue):
while not no_more_output.acquire(False):
b=os.read(nodejs.stdout.fileno(), READ_BYTES_SIZE)
if b:
output_queue.put(b)
# get the output from nodejs's stderr and continue till error output ends
def get_error(error_queue):
while not no_more_error.acquire(False):
b = os.read(nodejs.stderr.fileno(), READ_BYTES_SIZE)
if b:
error_queue.put(b)
# Threads managing nodejs.stdin, nodejs.stdout and nodejs.stderr respectively
input_thread = threading.Thread(target=put_input, args=(input_queue,))
input_thread.start()
output_thread = threading.Thread(target=get_output, args=(output_queue,))
output_thread.start()
error_thread = threading.Thread(target=get_error, args=(error_queue,))
error_thread.start()
# mark if output/error is ready
output_ready=False
error_ready=False
while (len(wselect) + len(rselect)) > 0:
try:
if nodejs.stdin in wselect:
if not input_queue.empty():
os.write(nodejs.stdin.fileno(), input_queue.get())
elif not input_thread.is_alive():
wselect = []
if nodejs.stdout in rselect:
if not output_queue.empty():
output_ready = True
stdout_buf.write(output_queue.get())
elif output_ready:
rselect = []
no_more_output.release()
no_more_error.release()
output_thread.join()
if nodejs.stderr in rselect:
if not error_queue.empty():
error_ready = True
stderr_buf.write(error_queue.get())
elif error_ready:
rselect = []
no_more_output.release()
no_more_error.release()
output_thread.join()
error_thread.join()
if stdout_buf.getvalue().endswith("\n"):
rselect = []
no_more_output.release()
no_more_error.release()
output_thread.join()
except OSError as e:
break
Так что лучший вариант для меня - это темы. Эта статья будет nice read, если вы хотите узнать больше.
Отметьте этот ответ http://stackoverflow.com/a/30172682/735893 – Vader
Спасибо за быстрый ответ! Я уже видел этот пост. Я думаю, что это не для выигрышных систем. – Py42
@Vader: эта ссылка использует 'fcntl', которая является UNIX-специфичной, OP использует Windows. – cdarke