2013-10-17 34 views
0

我的理解是,Python中的子進程無法訪問主進程的STDIN(支持該參數的參考問題:Python using STDIN in child ProcessIs there any way to pass 'stdin' as an argument to another process in python?)。python multiprocessing.pool的地圖訪問stdin如何?

但是,在下面的一段代碼中,我可以使用map將STDIN發送到進程池。有人可以澄清這是如何不同?

import multiprocessing 
import fileinput 

def test(line): 
    print line 

p = multiprocessing.Pool() 
p.map(test, fileinput.input()) 

回答

3

Pool.map將處理以手每個進程列表在一個時間的一個*構件在主過程中的輸入表(或其它可迭代)。所以,你的例子等同於以下情況:

import multiprocessing 
import fileinput 

def test(line): 
    print line 

input = [] 
for line in fileinput.input(): 
    input.append(line) 

p = multiprocessing.Pool() 
p.map(test, input) 

在它是真實的子進程不會讀取stdin什麼。

*除非您指定chunksize,在這種情況下,它每次處理一堆列表成員。


話雖這麼說,孩子進程無法訪問stdin這是不正確的。如果一般情況下這是真的,那麼例如UNIX shell就沒有多大用處。實際上,子進程繼承父母的文件描述符。因此父母和孩子都可以從相同的輸入源讀取。但問題在於一塊輸入數據只能被讀取一次,所以問題不在於從子項訪問stdin,而是決定哪個進程讀取哪些數據。在許多情況下,這是困難的,因此也是不可靠的(例如,如果您通過緩衝區讀取數據,例如通過許多編程語言的標準庫子例程)。

它,我想,針對上述原因,multiprocessing模塊的作者決定關閉sys.stdin(如標準庫對象通過它你可以閱讀stdin)的子進程,並迫使你放棄目標功能的輸入數據更安全的方式(例如通過multiprocessing.Queue)。但是有一個解決辦法,只要你確切地知道你的孩子進程將如何訪問stdin,這會爲你的父進程打開以及任何文件工作:

import os, sys, multiprocessing 

def square(num): 
    if num == 3: 
     num = int(raw_input('square what? ')) 
    return num ** 2 

def initialize(fd): 
    sys.stdin = os.fdopen(fd) 

initargs = [sys.stdin.fileno()] 
pool = multiprocessing.Pool(5, initialize, initargs) 

因此,舉例來說,如果我們發送的數字從1至10到池中每個五道工序都將收到一個數字,一次一個,但得到的3號將提示輸入的過程:

>>> pool.map(square, range(10))) 
square what? 9 
[0, 1, 4, 81, 16, 25, 36, 49, 64, 81] 

只是要小心不要有多個子進程在同一時間從同一個描述符讀取或者事情可能會變得令人困惑。

+0

作爲「多處理」模塊的作者決定閱讀[源代碼](http://hg.python.org/cpython/file/6d12285e250b/Lib/multiprocessing/process.py#l237)的參考文獻可以說明問題。 – kouk