含weakrefs的OpenMDAO问题用pygmo并行运行时变量为None如何解决?
解决OpenMDAO并行化中弱引用导致序列化丢失的问题
问题根源
你遇到的NoneType问题,本质是弱引用(weakrefs)在跨进程序列化/反序列化时无法正确重建。弱引用本身不持有对象的强引用,一旦原对象被GC回收,或者跨进程传递时没法把引用链带过去,反序列化后就会变成None。OpenMDAO内部部分组件靠弱引用做状态跟踪,直接用Dill或pygmo跨进程传实例,肯定会出问题。
针对Dill序列化的修复
- 把弱引用换成强引用:检查你代码里手动写的
weakref.ref()或者weakproxy,如果这些对象是并行计算必须的,直接改成强引用。要是怕循环引用,就用__getstate__和__setstate__自定义序列化逻辑:class MyComponent(ExplicitComponent): def __init__(self): super().__init__() self._strong_ref = some_obj # 换成强引用 self._weak_ref = weakref.ref(some_obj) # 保留弱引用供内部用 def __getstate__(self): state = self.__dict__.copy() del state['_weak_ref'] # 序列化时删掉弱引用 return state def __setstate__(self, state): self.__dict__.update(state) self._weak_ref = weakref.ref(self._strong_ref) # 反序列化后重建弱引用 - 让Dill递归序列化弱引用关联对象:开Dill的递归设置,强制把弱引用指向的对象也序列化进去,避免丢引用:
import dill dill.settings['recurse'] = True # 之后再序列化你的问题实例 serialized_data = dill.dumps(your_openmdao_problem)
适配pygmo并行优化的方案
pygmo跨进程分任务时会自动序列化问题实例,得确保你的OpenMDAO实例能被正确序列化:
- 先做可序列化的深拷贝:用开了递归设置的Dill先拷贝一份问题实例,再传给pygmo:
import dill from pygmo import problem, population, algorithm dill.settings['recurse'] = True # 先序列化再反序列化,得到干净的可并行实例 serializable_prob = dill.loads(dill.dumps(your_openmdao_prob)) # 包装成pygmo问题 pg_problem = problem(serializable_prob) # 正常跑并行优化 pop = population(pg_problem, size=10) algo = algorithm(...) pop = algo.evolve(pop) - 写个pygmo包装类:要是直接传问题实例还是不行,就写个包装类,只传配置参数,每个进程里自己重建OpenMDAO问题:
class PygmoOpenMDAOProblem: def __init__(self, problem_config): self.config = problem_config # 只传配置字典,不传完整问题 def fitness(self, x): # 每个进程里重新建问题 prob = self._build_problem(self.config) prob.set_val('des_vars', x) prob.run_model() return [prob.get_val('obj')] @staticmethod def _build_problem(config): # 这里写根据配置重建OpenMDAO问题的逻辑 prob = Problem() # 添加组件、设置驱动、加约束这些操作 return prob # 用的时候传配置就行 pg_problem = problem(PygmoOpenMDAOProblem(your_config_dict))
额外提醒
- 升级OpenMDAO:旧版本的组件可能有弱引用序列化的bug,更到最新稳定版说不定直接解决问题。
- 关组件缓存:如果你的组件用了基于弱引用的缓存,并行模式下直接关掉,避免引用丢失。
内容的提问来源于stack exchange,提问作者IgS2023
相关产品推荐
相关产品推荐

