Многопроцессорный ввод в Python
Весь код написан и протестирован на python 3.4 windows 7.
Я разрабатывал консольное приложение, и мне нужно было использовать стандартный ввод командной строки (win os) для выдачи команд и изменения режима работы программы. Программа зависит от многопроцессорности, чтобы справляться с нагрузками, связанными с процессором, и распространяться на несколько процессоров.
Я использую stdout для мониторинга этого состояния и некоторую базовую информацию о возвращении и stdin для выдачи команд для загрузки различных подпроцессов на основе возвращенной информации консоли.
Вот где я нашел проблему. Я не мог заставить многопроцессорный модуль принимать входные данные стандартного ввода, но стандартный вывод работал просто отлично. Я думаю, что нашел следующую справку по стеку, поэтому я проверил ее и обнаружил, что с модулем потоков это все прекрасно работает, за исключением того факта, что весь вывод в stdout приостанавливается до тех пор, пока каждый цикл stdin не будет циклически вызван блокировкой GIL с блокировкой stdin.
Я скажу, что я успешно справился с обходом, реализованным с помощью msvcrt.kbhit(). Однако я не могу не задаться вопросом, есть ли какая-то ошибка в многопроцессорной функции, которая заставляет stdin не читать какие-либо данные. Я пробовал множество способов, но при многопроцессорной обработке ничего не получалось. Даже пытался использовать Очереди, но я не пробовал пулы или какие-либо другие методы многопроцессорной обработки.
Я также не пробовал это на моей машине Linux, так как я сосредоточился на том, чтобы заставить его работать.
Вот упрощенный тестовый код, который не работает должным образом (напомним, это было написано в Python 3.4 - win7):
import sys
import time
from multiprocessing import Process
def function1():
while True:
print("Function 1")
time.sleep(1.33)
def function2():
while True:
print("Function 2")
c = sys.stdin.read(1) # Does not appear to be waiting for read before continuing loop.
sys.stdout.write(c) #nothing in 'c'
sys.stdout.write(".") #checking to see if it works at all.
print(str(c)) #trying something else, still nothing in 'c'
time.sleep(1.66)
if __name__ == "__main__":
p1 = Process(target=function1)
p2 = Process(target=function2)
p1.start()
p2.start()
Надеюсь, кто-то сможет пролить свет на то, предназначена ли эта функциональность, если я ее неправильно реализовал, или какую-то другую полезную информацию.
Благодарю.
1 ответ
Когда вы посмотрите на реализацию Pythons multiprocessing.Process._bootstrap()
вы увидите это:
if sys.stdin is not None:
try:
sys.stdin.close()
sys.stdin = open(os.devnull)
except (OSError, ValueError):
pass
Вы также можете подтвердить это, используя:
>>> import sys
>>> import multiprocessing
>>> def func():
... print(sys.stdin)
...
>>> p = multiprocessing.Process(target=func)
>>> p.start()
>>> <_io.TextIOWrapper name='/dev/null' mode='r' encoding='UTF-8'>
И чтение из os.devnull
немедленно возвращает пустой результат:
>>> import os
>>> f = open(os.devnull)
>>> f.read(1)
''
Вы можете обойти это, используя open(0)
:
file - это либо строковый, либо байтовый объект, задающий имя пути (абсолютное или относительное к текущему рабочему каталогу) открываемого файла или целочисленный дескриптор файла для оборачиваемого файла. (Если задан файловый дескриптор, он закрывается, когда возвращаемый объект ввода-вывода закрывается, если для closefd не установлено значение False.)
Файловые дескрипторы - это маленькие целые числа, соответствующие файлу, который был открыт текущим процессом. Например, стандартный ввод - это обычно дескриптор файла 0, стандартный вывод - 1, а стандартная ошибка - 2:
>>> def func():
... sys.stdin = open(0)
... print(sys.stdin)
... c = sys.stdin.read(1)
... print('Got', c)
...
>>> multiprocessing.Process(target=func).start()
>>> <_io.TextIOWrapper name=0 mode='r' encoding='UTF-8'>
Got a