2015-06-01 4 views
1

Я пытаюсь прочитать из sys.stdin изнутри объекта Python Process, но я продолжаю получать результат «ValueError: I/O operation on closed file». Вот простой пример:Чтение из stdin в Python Process?

import sys 
from multiprocessing import Process 

def do_something(input_data): 
    for x in input_data: 
     print x 


input=sys.stdin 

p = Process(target=do_something, args=(input,)) 
p.start() 
p.join() #Wait for Process to complete 

Данный скрипт всегда терпит неудачу с:

Traceback (most recent call last): 
    File "/usr/local/Cellar/python/2.7.5/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/process.py", line 258, in _bootstrap 
    self.run() 
    File "/usr/local/Cellar/python/2.7.5/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/process.py", line 114, in run 
    self._target(*self._args, **self._kwargs) 
    File "example.py", line 6, in do_something 
    for x in input_data: 
ValueError: I/O operation on closed file 

Просто вызова do_something(input) отлично работает без использования процесса, конечно. Создание объекта Pipe(), похоже, помогает - я могу написать содержимое stdin в Pipe и получить результаты в форме строки из процесса, но мне действительно нужен вход в файловую форму для некоторых последующих операций. Я мог бы сбрасывать содержимое в файл и перечитывать его изнутри Процесса, но это кажется довольно неуклюжим, особенно если stdin действительно большой. Есть ли простой способ прочитать из sys.stdin изнутри процесса?

ответ

0

Вы должны закрыть файл, который вы пытаетесь записать, в какой-то момент. Проверьте свой код и попробуйте удалить все строки, которые закрывают файлы (fileVariableName .close()) и посмотреть, работает ли он. Если это так, повторите добавление их один за другим, чтобы найти проблему. После того, как вы нашли строку, вызывающую проблемы, попробуйте переместить ее дальше в программу (назовите ее позже) и посмотрите, устраняет ли это ваши проблемы.

EDIT: изменение

def do_something(input_data): 
    for x in input_data: 
     print x 

в

def do_something(): 
    for x in sys.stdin: 
     print x 

и избавиться от input = sys.stdin

+0

Пример кода, который я опубликовал, демонстрирует проблему, но не содержит явных закрытий файлов, поэтому я уверен, что это не так. Также помните, что «файл» - это sys.stdin, а не обычный файл. – homesalad

+0

Попробуйте изменить 'input = sys.stdin' на' input = sys.stdin.readlines() ' – NendoTaka

+0

Это помогает, но он читает все stdin в памяти, прежде чем продолжить, что является поведением, которое я надеюсь избежать.Вход может быть очень большим, и я бы не прочитал его все до начала процесса. – homesalad

2

Это происходит потому, что перед началом процесса, stdin закрыт. В противном случае может случиться так, что как родительский, так и дочерний процессы (или несколько дочерних процессов) пытаются читать из одного и того же stdin, что является плохой идеей.

В дочернем процессе sys.stdin фактически перенаправлены /dev/null:

from multiprocessing import Process 
import sys 

def test(*args): 
    print(args) 
    print(sys.stdin, sys.stdin.fileno()) 

if __name__ == '__main__': 
    p = Process(target=test, args=(sys.stdin,)) 
    p.start() 
    p.join() 

должны напечатать что-то похожее на это:

(<closed file '<stdin>', mode 'r' at 0x7f3b4564b0c0>,) 
(<open file '/dev/null', mode 'r' at 0x7f3b43a9e0c0>, 3) 

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

Вы можете обойти эту проблему с помощью os.dup() на sys.stdin.fileno() в родительском и передать возвращенную копию дескриптора файла для ребенка в качестве аргумента, где вы можете использовать os.fdopen() для работы с ним.

Решение для очистки, вероятно, должно было бы прочитать ввод в родительском процессе и pass it to the child с использованием multiprocessing.Queue.

Смежные вопросы