以下程序:
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/