Подтвердить что ты не робот

Есть ли способ передать "stdin" в качестве аргумента для другого процесса в python?

Я пытаюсь создать script, который использует многопроцессорный модуль с python. script (позволяет вызывать его myscript.py) получит вход от другого script с помощью pipe.

Предположим, что я вызываю скрипты следующим образом:

$ python writer.py | python myscript.py 

И вот коды;

// writer.py
import time, sys

def main():
    while True:
        print "test"
        sys.stdout.flush()
        time.sleep(1)

main()

//myscript.py
def get_input():
    while True:
        text = sys.stdin.readline()
        print "hello " + text
        time.sleep(3)

if __name__ == '__main__':        
    p1 = Process(target=get_input, args=())
    p1.start()

это явно не работает, поскольку объекты sys.stdin отличаются для основного процесса и p1. Поэтому я попытался это решить,

//myscript.py
def get_input(temp):
    while True:
        text = temp.readline()
        print "hello " + text
        time.sleep(3)

if __name__ == '__main__':        
    p1 = Process(target=get_input, args=(sys.stdin,))
    p1.start()

но я сталкиваюсь с этой ошибкой;

Process Process-1:
Traceback (most recent call last):
  File "/usr/lib/python2.7/multiprocessing/process.py", line 258, in _bootstrap
    self.run()
  File "/usr/lib/python2.7/multiprocessing/process.py", line 114, in run
    self._target(*self._args, **self._kwargs)
  File "in.py", line 12, in get_input
    text = temp.readline()
ValueError: I/O operation on closed file

Итак, я думаю, что основной файл stdin закрыт, и я не могу его прочитать. В этом соединении, как я могу передать главный файл stdin другому процессу? Если передача stdin невозможна, как я могу использовать главный stdin из другого процесса?

обновление: Хорошо, мне нужно уточнить свой вопрос, так как люди думают, что использование многопроцессорности не является действительно необходимым. рассмотрим myscript.py следующим образом:

//myscript.py
def get_input():
    while True:
        text = sys.stdin.readline()
        print "hello " + text
        time.sleep(3)

def do_more_things():
    while True:
        #// some code here
        time.sleep(60*5)

if __name__ == '__main__':        
    p1 = Process(target=get_input, args=())
    p1.start()

    do_more_things()

поэтому мне действительно нужно запустить функцию get_input() параллельно с главной функцией (или другими подпроцессами). Извините за конфликты, у меня приличный английский, и я думаю, что я не мог понять этот вопрос. Я был бы признателен, если вы, ребята, можете сказать мне, могу ли я использовать основной процесс объекта STDIN в другом процессе.

заблаговременно.

4b9b3361

Ответ 1

Самое простое - обменять get_input() и do_more_things(), т.е. прочитать sys.stdin в родительском процессе:

def get_input(stdin):
    for line in iter(stdin.readline, ''):
        print("hello", line, end='')
    stdin.close()

if __name__ == '__main__':
    p1 = mp.Process(target=do_more_things)
    p1.start()
    get_input(sys.stdin)

Следующее лучшее - использовать Thread() вместо Process() для get_input():

if __name__ == '__main__':
    t = Thread(target=get_input, args=(sys.stdin,))
    t.start()
    do_more_things()

Если приведенное выше не поможет, попробуйте os.dup():

newstdin = os.fdopen(os.dup(sys.stdin.fileno()))
try: 
   p = Process(target=get_input, args=(newstdin,))
   p.start()    
finally:
   newstdin.close() # close in the parent
do_more_things()

Ответ 2

Каждый новый процесс, созданный с помощью модуля многопроцессорности, получает свой собственный PID и, следовательно, имеет собственное устройство ввода и устройства вывода, даже если они оба пишут на один и тот же терминал, следовательно, требуется блокировка.

Вы уже создали два процесса, разделив содержимое на два сценария и создав третий процесс с помощью get_input(). get_input мог читать стандартный ввод, если это был поток, а не процесс. Тогда нет необходимости иметь функцию сна в читателе.

## reader.py
from threading import Thread
import sys

def get_input():
    text = sys.stdin.readline()
    while len(text) != 0:
        print 'hello ' + text
        text = sys.stdin.readline()

if __name__ == '__main__':
    thread = Thread(target=get_input)
    thread.start()
    thread.join()

Ответ 3

Это будет лишь частичным ответом - поскольку я неясен о последующих частях вопроса.

Вы начинаете с того, что ожидаете называть свои скрипты:

$ python writer.py | python myscript.py 

Если вы собираетесь это сделать, писателю нужно написать стандартную версию, а myscript нужно читать со стандартного ввода. Второй script будет выглядеть так:

def get_input():
    while True:
        text = sys.stdin.readline()
        print "hello " + text
        time.sleep(3)
if __name__ == '__main__':    
    get_input()

Нет необходимости в многопроцессорном объекте .Process... вы уже отключили два процесса из командной строки - и вы используете оболочку для подключения к ней (анонимный) канал (символ "|" ), который соединяет стандартный вывод с первого script со стандартным входом со второго script.

Точкой объекта Process является управление запуском второго процесса с первого. Вам нужно будет определить процесс; затем запустите его - тогда вы, вероятно, захотите подождать, пока он не завершится до выхода из первого процесса... (вызов p1.join() после того, как для этого будет достаточно p1.start()).

Если вы хотите установить связь между двумя процессами под управлением python, вы, вероятно, захотите использовать объект multiprocess.Pipe для выполнения так. Затем вы можете легко общаться между inital и подчиненным порожденным процессом, читая и записывая в/из объекта Pipe, а не стандартный ввод и стандартный вывод. Если вы действительно хотите перенаправить стандартный ввод и стандартный вывод, это, вероятно, возможно, возившись с низкоуровневыми файловыми дескрипторами и/или переопределяя/заменяя объекты sys.stdin и sys.stdout... но, я подозреваю, вы, вероятно, не хотите (или нуждаетесь) для этого.

Ответ 4

Чтобы прочитать каналы, используемые во входных данных, используйте fileinput:

myscript.py

import fileinput

if __name__ == '__main__':
    for line in fileinput.input():
        #do stuff here
        process_line(line)