0

我的理解是 Python 中的子进程无法访问主进程的 STDIN(支持此论点的参考问题:Python using STDIN in child Process and Is there any way to pass 'stdin' as a 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())
4

1 回答 1

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.

* 除非您指定 achunksize在这种情况下,它会一次将一组列表成员交给每个进程。


话虽如此,子进程无法访问是不正确的stdin。如果这通常是正确的,那么例如 UNIX shell 将没有多大用处。实际上,子进程继承其父进程的文件描述符。因此,父母和孩子都可以从同一个输入源进行阅读。但问题是一段输入数据只能被读取一次,所以问题不在于stdin子进程的访问,而是决定哪个进程读取什么数据。在许多情况下,这很困难,因此不可靠(例如,如果您通过缓冲区读取数据,例如通过许多编程语言的标准库子例程)。

我想,出于上述原因,multiprocessing模块的作者决定在子进程中关闭sys.stdin(例如,您可以读取的标准库对象stdin)并强制您以更安全的方式(例如 via 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]

请注意不要让多个子进程同时从同一个描述符中读取,否则事情可能会变得......混乱。

于 2013-10-17T06:58:52.483 回答