以下程序:

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

为什么会出现错误(在Linux x64上的cPython 2.7和3.2上),如果我取消注释第三行,为什么它会消失?

最佳答案

这里的问题是,多处理模块通过复制将对象传递给其他进程(很明显),并且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与复制新的itemgetter几乎一样容易且有效。这就是您替代的“f”函数正在执行的操作。 (当然,复制动态创建itemgetter的函数不需要复制itemgetter。)

您可以将“f”转换为lambda。或编写一个琐碎的函数(名为lambda),而无需使用itemgetter即可执行相同的操作。或编写一个可复制的itemgetter替代品(显然不会那么难)。但是您不能像您想要的那样直接使用itemgetter对象。

关于python - 为什么不能在multiprocessing.Pool中使用operator.itemgetter?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11235054/

10-12 22:43