Can';t pickle静态方法-多处理-Python
我正在对我的代码应用一些并行化,在其中我使用类。我知道如果没有Python提供的任何其他方法,就不可能选择一个类方法。我找到了解决办法。在我的代码中,我必须使用类来定义应该并行化的部分。在这里,我发布了一个非常简单的代码,只代表我的结构(是一样的,但我删除了方法的内容,这是大量的数学演算,对我得到的输出无关紧要)。问题是因为我可以pickle一种方法(shepard_插值),但用另一种方法(计算方向不确定性),我得到了pickle误差。我不知道为什么会发生这种情况,也不知道为什么会部分起作用Can';t pickle静态方法-多处理-Python,python,class,multiprocessing,pickle,pool,Python,Class,Multiprocessing,Pickle,Pool,我正在对我的代码应用一些并行化,在其中我使用类。我知道如果没有Python提供的任何其他方法,就不可能选择一个类方法。我找到了解决办法。在我的代码中,我必须使用类来定义应该并行化的部分。在这里,我发布了一个非常简单的代码,只代表我的结构(是一样的,但我删除了方法的内容,这是大量的数学演算,对我得到的输出无关紧要)。问题是因为我可以pickle一种方法(shepard_插值),但用另一种方法(计算方向不确定性),我得到了pickle误差。我不知道为什么会发生这种情况,也不知道为什么会部分起作用 d
def _pickle_method(method):
func_name = method.im_func.__name__
obj = method.im_self
cls = method.im_class
if func_name.startswith('__') and not func_name.endswith('__'): #deal with mangled names
cls_name = cls.__name__.lstrip('_')
func_name = '_' + cls_name + func_name
print cls
return _unpickle_method, (func_name, obj, cls)
def _unpickle_method(func_name, obj, cls):
for cls in cls.__mro__:
try:
func = cls.__dict__[func_name]
except KeyError:
pass
else:
break
return func.__get__(obj, cls)
class ImageData(object):
def __init__(self, width=60, height=60):
self.width = width
self.height = height
self.data = []
for i in range(width):
self.data.append([0] * height)
def shepard_interpolation(self, seeds=20):
print "ImD - Sucess"
import copy_reg
import types
from itertools import product
from multiprocessing import Pool
copy_reg.pickle(types.MethodType, _pickle_method, _unpickle_method)
class VariabilityOfGradients(object):
def __init__(self):
pass
@staticmethod
def aux():
return "VoG - Sucess"
@staticmethod
def calculate_orientation_uncertainty():
results = []
pool = Pool()
for x, y in product(range(1, 5), range(1, 5)):
result = pool.apply_async(VariabilityOfGradients.aux)
results.append(result.get())
pool.close()
pool.join()
if __name__ == '__main__':
results = []
pool = Pool()
for _ in range(3):
result = pool.apply_async(ImageData.shepard_interpolation, args=[ImageData()])
results.append(result.get())
pool.close()
pool.join()
VariabilityOfGradients.calculate_orientation_uncertainty()
运行时,我得到“PicklingError:Can't pickle:attribute lookupbuiltin。函数失败”。这几乎是相同的发现。我看到的唯一区别是我的方法是静态的
编辑:
我注意到,在我的calculate\u orientation\u不确定性中,当我将函数调用为result=pool.apply\u async(VariabilityOfGradients.aux())
,也就是说,使用括号(在文档示例中我从未看到过),它似乎可以工作。但是,当我试图得到结果时,我收到“TypeError:'int'对象不可调用”
任何帮助都将不胜感激。提前感谢。您可以在模块级别定义普通函数,也可以定义静态方法。这保留了staticmethod的调用语法、内省和可继承性特性,同时避免了pickle问题:
def aux():
return "VoG - Sucess"
class VariabilityOfGradients(object):
aux = staticmethod(aux)
比如说,
import copy_reg
import types
from itertools import product
import multiprocessing as mp
def _pickle_method(method):
"""
Author: Steven Bethard (author of argparse)
http://bytes.com/topic/python/answers/552476-why-cant-you-pickle-instancemethods
"""
func_name = method.im_func.__name__
obj = method.im_self
cls = method.im_class
cls_name = ''
if func_name.startswith('__') and not func_name.endswith('__'):
cls_name = cls.__name__.lstrip('_')
if cls_name:
func_name = '_' + cls_name + func_name
return _unpickle_method, (func_name, obj, cls)
def _unpickle_method(func_name, obj, cls):
"""
Author: Steven Bethard
http://bytes.com/topic/python/answers/552476-why-cant-you-pickle-instancemethods
"""
for cls in cls.mro():
try:
func = cls.__dict__[func_name]
except KeyError:
pass
else:
break
return func.__get__(obj, cls)
copy_reg.pickle(types.MethodType, _pickle_method, _unpickle_method)
class ImageData(object):
def __init__(self, width=60, height=60):
self.width = width
self.height = height
self.data = []
for i in range(width):
self.data.append([0] * height)
def shepard_interpolation(self, seeds=20):
print "ImD - Success"
def aux():
return "VoG - Sucess"
class VariabilityOfGradients(object):
aux = staticmethod(aux)
@staticmethod
def calculate_orientation_uncertainty():
pool = mp.Pool()
results = []
for x, y in product(range(1, 5), range(1, 5)):
# result = pool.apply_async(aux) # this works too
result = pool.apply_async(VariabilityOfGradients.aux, callback=results.append)
pool.close()
pool.join()
print(results)
if __name__ == '__main__':
results = []
pool = mp.Pool()
for _ in range(3):
result = pool.apply_async(ImageData.shepard_interpolation, args=[ImageData()])
results.append(result.get())
pool.close()
pool.join()
VariabilityOfGradients.calculate_orientation_uncertainty()
屈服
ImD - Success
ImD - Success
ImD - Success
['VoG - Sucess', 'VoG - Sucess', 'VoG - Sucess', 'VoG - Sucess', 'VoG - Sucess', 'VoG - Sucess', 'VoG - Sucess', 'VoG - Sucess', 'VoG - Sucess', 'VoG - Sucess', 'VoG - Sucess', 'VoG - Sucess', 'VoG - Sucess', 'VoG - Sucess', 'VoG - Sucess', 'VoG - Sucess']
顺便说一下,在
池.apply_async
(例如ImageData.shepard_interpolation
)调用的函数完成之前,会阻止调用过程。所以
for _ in range(3):
result = pool.apply_async(ImageData.shepard_interpolation, args=[ImageData()])
results.append(result.get())
实际上是按顺序调用ImageData.shepard_interpolation
,这违背了池的目的
相反,你可以使用
for _ in range(3):
pool.apply_async(ImageData.shepard_interpolation, args=[ImageData()],
callback=results.append)
回调函数(例如,results.append
)在函数完成时在调用过程的线程中调用。它被发送一个参数——函数的返回值。因此,没有任何东西会阻止这三个池。apply_async
调用的快速进行,对ImageData.shepard_interpolation
的三个调用所做的工作将同时执行
或者,在这里使用pool.map
可能更简单
results = pool.map(ImageData.shepard_interpolation, [ImageData()]*3)
如果使用名为
pathos.multiprocessing
的多处理
分支,则可以在多处理的映射
函数中直接使用类和类方法。这是因为使用了dill
而不是pickle
或cPickle
,并且dill
几乎可以序列化python中的任何内容
pathos.multi-processing
还提供了一个异步映射函数…它可以map
具有多个参数的函数(例如map(math.pow,[1,2,3],[4,5,6])
)
见:
以及:
在此处获取代码:
pathos
也有一个异步映射(amap
),以及imap
我不确定这是否是您想要的,但我的使用略有不同。我想使用同一个类中运行在多个线程上的类的方法
我就是这样实现的:
from multiprocessing import Pool
class Product(object):
def __init__(self):
self.logger = "test"
def f(self, x):
print(self.logger)
return x*x
def multi(self):
p = Pool(5)
print(p.starmap(Product.f, [(Product(), 1), (Product(), 2), (Product(), 3)]))
if __name__ == '__main__':
obj = Product()
obj.multi()
如果这不是您的代码,人们很可能会要求您发布您遇到问题的确切代码。只是一个通知。另外,您使用的是哪一个Python版本,pickle在版本中的行为有点不同,我个人认为,只要类对象不包含套接字或活动线程之类的实例,pickle就不会有问题。通常,您将一个线程化类存储在两个类对象中,一个可能继承另一个,或者只是在线程化类中初始化一个类,如果有意义的话,只在“内部”类中线程化。这是我的代码。我只是删除了方法中的内容(对问题来说无关紧要,大量的数学运算是不必要的)。错误消息是什么?@pceccon:关于编辑:如果使用
pool.apply_async(variabilityofgradens.aux())
那么首先调用variabilityofgradens.aux()
,然后将其返回值发送到池。应用\u async
。这不是您想要的,因为池工作程序没有同时调用VariabilityOfGradients.aux
。关于原始问题:isinstance(func,types.MethodType)
是False
当func
是静态方法时,所以copy\u reg.pickle(types.MethodType,\u pickle\u method,\u unpickle\u method)
不影响静态方法。简单的解决方法是在全局模块级别将staticmethod设置为普通函数。我知道这一点,但我只是想知道是否有一种方法可以在Python中实现我想要的功能,而不是使用这种方法。但似乎我不能。你好,@unutbu。我能再问你一件事吗?它工作了,但是,正如您所看到的,在这个示例中,我迭代了25次。在我的问题中,我有两个200 x 200的for,我的aux函数有很多数学处理。正在发生的事情是,调用这个并行化程序要比根本不使用多处理程序花费更多的时间。你知道为什么吗?我在本例中应用的概念正确吗?谢谢。你能把有问题的代码发出去吗?可运行的代码会有很大帮助。
from multiprocessing import Pool
class Product(object):
def __init__(self):
self.logger = "test"
def f(self, x):
print(self.logger)
return x*x
def multi(self):
p = Pool(5)
print(p.starmap(Product.f, [(Product(), 1), (Product(), 2), (Product(), 3)]))
if __name__ == '__main__':
obj = Product()
obj.multi()