python multiprocessing.pool的map如何访问stdin?

时间:2013-10-17 05:41:31

标签: python multiprocessing

我的理解是Python中的子进程无法访问主进程的STDIN(参考支持此参数的问题:Python using STDIN in child ProcessIs there any way to pass 'stdin' as an argument to another process in python?)。

但是在下面的代码中,我可以使用map将STDIN发送到进程池。有人可以澄清一下这有什么不同吗?

import multiprocessing 
import fileinput

def test(line):
    print line

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

1 个答案:

答案 0 :(得分: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]

请注意不要让多个子进程同时从同一个描述符中读取,否则可能会让人感到困惑。