Python multiprocessing.Pool:AttributeError
Posted
技术标签:
【中文标题】Python multiprocessing.Pool:AttributeError【英文标题】:Python multiprocessing.Pool: AttributeError 【发布时间】:2019-02-15 07:42:00 【问题描述】:我在一个类中有一个方法需要在一个循环中做很多工作,我想把工作分散到我所有的核心上。
我编写了以下代码,如果我使用普通的map()
,它可以工作,但使用pool.map()
会返回错误。
import multiprocessing
pool = multiprocessing.Pool(multiprocessing.cpu_count() - 1)
class OtherClass:
def run(sentence, graph):
return False
class SomeClass:
def __init__(self):
self.sentences = [["Some string"]]
self.graphs = ["string"]
def some_method(self):
other = OtherClass()
def single(params):
sentences, graph = params
return [other.run(sentence, graph) for sentence in sentences]
return list(pool.map(single, zip(self.sentences, self.graphs)))
SomeClass().some_method()
错误一:
AttributeError: Can't pickle local object 'SomeClass.some_method..single'
为什么不能腌制single()
?我什至尝试将 single()
移动到全局模块范围(不在类内部 - 使其独立于上下文):
import multiprocessing
pool = multiprocessing.Pool(multiprocessing.cpu_count() - 1)
class OtherClass:
def run(sentence, graph):
return False
def single(params):
other = OtherClass()
sentences, graph = params
return [other.run(sentence, graph) for sentence in sentences]
class SomeClass:
def __init__(self):
self.sentences = [["Some string"]]
self.graphs = ["string"]
def some_method(self):
return list(pool.map(single, zip(self.sentences, self.graphs)))
SomeClass().some_method()
我得到以下信息......
错误2:
AttributeError: Can't get attribute 'single' on module 'main' from '.../test.py'
【问题讨论】:
无论如何,对于您的原始代码:酸洗局部函数通常不起作用,尽管细节很复杂——而且,为了使调试更有趣,如果任何捕获的变量的值可以'不要被腌制,你会收到一条错误消息,它引用的是函数而不是那个值。 解决办法是把它变成一个方法或者一个全局函数,并把delex
作为参数传入(你可以functools.partial
)而不是捕获值。您的修改版本应该可以正常工作;问题是为什么它在data.SomeClass.reader
中查找,它看起来根本不像一个模块,而不是在模块中,大概是data
。你能给我们一个minimal reproducible example 那个版本吗?
@abarnert 我将这两个示例都更改为最小、完整和可验证,并更新了错误。它在data.SomeClass.reader
中查找的原因是因为这是文件的层次结构,因为我有多个数据源和每个数据源的阅读器。我删除了它,而是编写了一个具有相同错误的新类。
【参考方案1】:
错误 1:
AttributeError: Can't pickle local object 'SomeClass.some_method..single'
您通过将嵌套的目标函数 single()
移到顶层自己解决了这个错误。
背景:
Pool 需要腌制(序列化)它发送到其工作进程 (IPC) 的所有内容。 Pickling 实际上只保存函数的名称,而 unpickling 需要按名称重新导入函数。为此,需要在顶层定义函数,嵌套函数不能被子函数导入,并且已经尝试腌制它们会引发异常 (more)。
错误 2:
AttributeError: Can't get attribute 'single' on module 'main' from '.../test.py'
您在定义函数和类之前启动池,这样子进程就不能继承任何代码。将您的池启动移动到底部并使用 if __name__ == '__main__':
保护 (why?)
import multiprocessing
class OtherClass:
def run(self, sentence, graph):
return False
def single(params):
other = OtherClass()
sentences, graph = params
return [other.run(sentence, graph) for sentence in sentences]
class SomeClass:
def __init__(self):
self.sentences = [["Some string"]]
self.graphs = ["string"]
def some_method(self):
return list(pool.map(single, zip(self.sentences, self.graphs)))
if __name__ == '__main__': # <- prevent RuntimeError for 'spawn'
# and 'forkserver' start_methods
with multiprocessing.Pool(multiprocessing.cpu_count() - 1) as pool:
print(SomeClass().some_method())
附录
...我想把这项工作分散到我所有的核心。
关于 multiprocessing.Pool
如何进行分块工作的潜在有用背景:
Python multiprocessing: understanding logic behind chunksize
【讨论】:
完美。谢谢,我不知道 Pool 取决于位置【参考方案2】:我无意中发现了一个非常讨厌的解决方案。它有效,只要你
使用def
语句。如果您声明要在 Pool.map
中使用的函数,并在解决它的函数的开头使用 global
关键字。但我不会在严肃的应用程序中依赖它?
import multiprocessing
pool = multiprocessing.Pool(multiprocessing.cpu_count() - 1)
class OtherClass:
def run(sentence, graph):
return False
class SomeClass:
def __init__(self):
self.sentences = [["Some string"]]
self.graphs = ["string"]
def some_method(self):
global single # This is ugly, but does the trick XD
other = OtherClass()
def single(params):
sentences, graph = params
return [other.run(sentence, graph) for sentence in sentences]
return list(pool.map(single, zip(self.sentences, self.graphs)))
SomeClass().some_method()
【讨论】:
亲爱的上帝...安全吗?还是我会在single
上跨类的不同实例获得一些竞争条件?
当然不是。甚至不要考虑在生产代码中使用它... xD以上是关于Python multiprocessing.Pool:AttributeError的主要内容,如果未能解决你的问题,请参考以下文章