如何解决并行化时出现的‘cannot pickle local object’错误?
问题原因
出现Can't pickle local object 'aapy.U_matrix.<locals>.lsqSOLUTION'错误的核心原因是:Python标准库multiprocessing依赖pickle做对象序列化,但定义在函数内部的局部函数(闭包)无法被pickle序列化——它绑定了外部函数的上下文,没法独立传递给子进程。
解决方法
方法1:把局部函数改成类的顶层方法
将lsqSOLUTION从U_matrix内部移到类的顶层,变成类的方法,这样它就不再是局部函数,能被正常序列化。同时要把原来闭包用到的参数(self、V、iters、eabs)显式打包传递。
修正后的代码:
class YourClass: # 替换成你的实际类名 def U_matrix(self, V): U = np.zeros((0, self.c)) iters, eabs = 500, 0.01 # 把参数打包成元组,每个元组对应一个任务的参数 task_args = [(i, V, iters, eabs, self) for i in range(self.N)] with multiprocessing.Pool() as pool: u_list = pool.map(self.lsqSOLUTION, task_args) vector = np.array(u_list) U = np.vstack([U, vector]) # 修正vstack的调用方式(原代码传参错误) return U @staticmethod def lsqSOLUTION(task_args): i, V, iters, eabs, self_obj = task_args ui = cp.Variable((self_obj.c)) objective = cp.Minimize(cp.sum_squares(V @ ui - self_obj.Data[:, i])) constraints = [0 <= ui, ui <= 1, cp.sum(ui) == 1] prob = cp.Problem(objective, constraints) prob.solve(solver=cp.ECOS, max_iters=iters, abstol=eabs) return np.transpose(ui.value)
注意:
- 用
@staticmethod是因为这个方法不需要修改类/实例状态,要是需要访问实例方法,也可以换成实例方法,但要注意参数传递逻辑。 - 原代码里
np.vstack(U, vector)是错误用法,正确的是把要堆叠的数组放进列表里传入:np.vstack([U, vector])。
方法2:用模块级顶层函数+参数打包
如果不想调整类结构,把lsqSOLUTION定义成模块级的顶层函数,然后把所有需要的参数打包成元组传给pool.map。
代码示例:
# 把函数定义在模块最外层(类的外面) def lsqSOLUTION(task_args): i, V, iters, eabs, self_obj = task_args ui = cp.Variable((self_obj.c)) objective = cp.Minimize(cp.sum_squares(V @ ui - self_obj.Data[:, i])) constraints = [0 <= ui, ui <= 1, cp.sum(ui) == 1] prob = cp.Problem(objective, constraints) prob.solve(solver=cp.ECOS, max_iters=iters, abstol=eabs) return np.transpose(ui.value) class YourClass: def U_matrix(self, V): U = np.zeros((0, self.c)) iters, eabs = 500, 0.01 task_args = [(i, V, iters, eabs, self) for i in range(self.N)] with multiprocessing.Pool() as pool: u_list = pool.map(lsqSOLUTION, task_args) vector = np.array(u_list) U = np.vstack([U, vector]) return U
方法3:用第三方库支持局部函数序列化(可选)
如果不想改代码结构,可以用pathos.multiprocessing——它用dill替代pickle,支持序列化局部函数。先安装库:
pip install pathos
然后修改并行部分代码:
from pathos.multiprocessing import Pool def U_matrix(self, V): U = np.zeros((0, self.c)) iters, eabs = 500, 0.01 def lsqSOLUTION(i): ui = cp.Variable((self.c)) objective = cp.Minimize(cp.sum_squares(V @ ui - self.Data[:, i])) constraints = [0 <= ui, ui <= 1, cp.sum(ui) == 1] prob = cp.Problem(objective, constraints) prob.solve(solver=cp.ECOS, max_iters=iters, abstol=eabs) return np.transpose(ui.value) args = range(self.N) with Pool() as pool: u_list = pool.map(lsqSOLUTION, args) vector = np.array(u_list) U = np.vstack([U, vector]) return U
额外提示
- 如果在Windows系统下运行,记得把主程序入口放在
if __name__ == '__main__':块里,避免子进程重复执行模块代码。 - 尽量避免传递过大的对象到子进程,不然会拖慢性能。
内容的提问来源于stack exchange,提问作者Abdul Suleman
相关产品推荐
相关产品推荐

