为什么我不能在multiprocessing.Pool使用operator.itemgetter?(

2019-07-30 03:51发布

下面的程序:

import multiprocessing,operator
f = operator.itemgetter(0)
# def f(*a): return operator.itemgetter(0)(*a)
if __name__ == '__main__':
    multiprocessing.Pool(1).map(f, ["ab"])

失败,出现以下错误:

Process PoolWorker-1:
Traceback (most recent call last):
  File "/usr/lib/python3.2/multiprocessing/process.py", line 267, in _bootstrap
    self.run()
  File "/usr/lib/python3.2/multiprocessing/process.py", line 116, in run
    self._target(*self._args, **self._kwargs)
  File "/usr/lib/python3.2/multiprocessing/pool.py", line 102, in worker
    task = get()
  File "/usr/lib/python3.2/multiprocessing/queues.py", line 382, in get
    return recv()
TypeError: itemgetter expected 1 arguments, got 0

为什么我收到错误(上CPython的2.7和3.2在Linux 64位),以及为什么它消失,如果我去掉第三行?

Answer 1:

这里的问题是,该多处理模块经过复制物体进入其他处理(明显),和itemgetter对象使用任何明显的装置是不可拷贝:

In [10]: a = operator.itemgetter(0)
Out[10]: copy.copy(a)
TypeError: itemgetter expected 1 arguments, got 0

In [10]: a = operator.itemgetter(0)
Out[10]: copy.deepcopy(a)
TypeError: itemgetter expected 1 arguments, got 0

In [10]: a = operator.itemgetter(0)
Out[10]: pickle.dumps(a)
TypeError: can't pickle itemgetter objects

# etc.

这个问题甚至没有试图调用F其他进程内; 它试图把它摆在首位复制。 (如果你看一下堆栈跟踪,我在上面省略了,你就会明白为什么这个失败了更多的信息。)

当然,通常这并不重要,因为它几乎是一样方便,高效的构建移动新itemgetter因为复制一个。 这就是你选择的“F”功能做。 (复制是在飞行中产生的itemgetter的功能并不需要复制一个itemgetter,当然)。

你可以把“F”为lambda。 或写做同样的事情,而不使用itemgetter平凡函数(名为或lambda)。 或者写一个itemgetter替代品,是可复制(这显然不会是所有的辛苦)。 但你不能直接使用itemgetter对象作为,是你想要的方式。



文章来源: Why can't I use operator.itemgetter in a multiprocessing.Pool?