序列化Boost Python函数
为了使用joblib.Parallel,我需要能够对一个boost::python函数进行序列化(也就是把它变成可以保存和传输的格式)。
TypeError: can't pickle builtin_function_or_method objects
根据我的理解,这个函数应该只通过它的完整名称来进行序列化。我不明白为什么这不行。有没有什么想法?
2 个回答
0
问题在于,joblib 正在尝试将一个传给 joblib.delayed 的函数转换成 pickle 格式,但它无法转换 Boost.Python.function 对象。为了解决这个问题,你可以使用一个不直接包含 Boost.Python.function 的可调用对象。你可以参考 这个链接 中提到的方法,使用一个包装器来实现。
我在使用 rdkit 时遇到了这个问题。下面是一个在 2022 年有效的解决方案示例。
import importlib
from joblib import Parallel, delayed
class Wrapper:
def __init__(self, method_name, module_name):
self.method_name = method_name
self.module = importlib.import_module(module_name)
@property
def method(self):
return getattr(self.module, self.method_name)
def __call__(self, *args, **kwargs):
return self.method(*args, **kwargs)
wrapped_mol_from_smiles = Wrapper("MolFromSmiles", "rdkit.Chem")
smiles = ["CCC", "CC"]
mols = Parallel(n_jobs=2, backend="loky")(
delayed(wrapped_mol_from_smiles)(x) for x in smiles
)
print(mols)
2
如果你想在一个 joblib.Parallel 对象中使用你的 boost 方法,或许你可以给你的 boost 方法加一个包装器:
from joblib import Parallel, delayed
from boost import boost_function
class Wrapper(object):
def __init__(self, method_name, module_name):
self.method_name = method_name
self.module_name = module_name
def __call__(self, *args, **kwargs):
method = __import__(self.module_name, globals(), locals(), [self.method_name,])
return method(*args, **kwargs)
Parallel(n_jobs=1)(delayed(Wrapper("boost_module_name_with_dots", "boost_method_name")(i) for i in range(10))