Многопроцессорный ввод в 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 файловый дескриптор ":

Файловые дескрипторы - это маленькие целые числа, соответствующие файлу, который был открыт текущим процессом. Например, стандартный ввод - это обычно дескриптор файла 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
Другие вопросы по тегам