相同代码不同输入时joblib报cannot pickle 'weakref' object错误如何解决
核心原因
joblib使用默认loky多进程后端时,子进程的执行结果必须可被pickle序列化才能传回主进程,返回值的内部属性远比返回类型重要。两种测试场景返回类型均为music21.stream.Score没有差异,但是从真实文件解析出的Score对象内部包含不可序列化的weakref(弱引用)类型属性,才会触发序列化报错;人工构造的简单ABC片段解析出的Score对象无这类属性,所以可以正常运行。
解决方案(按优先级排序)
方案1:清理Score对象的不可序列化属性
music21原生提供了清理弱引用、缓存等不可序列化属性的方法,在返回前调用即可,无额外序列化反序列化成本,是最优解决方案:
def convert_string(string: str, format: str = "abc") -> music21.stream.Score: score = music21.converter.parse(string, format=format) # 清理所有弱引用、未使用的缓存属性 score.purge() # 可选补充:如果purge后仍有报错,额外清空内部缓存字典 if hasattr(score, '_cache'): score._cache = {} return score
方案2:替换序列化工具为dill
dill对Python各类非基础类型的序列化支持远好于默认的pickle/cloudpickle,无需修改业务逻辑,只需调整joblib参数即可:
- 首先安装dill:
pip install dill
- 修改
convert_list_of_strings的Parallel配置:
def convert_list_of_strings( string_list, n_jobs=-1, prefer=None ) -> List[music21.stream.Score]: return Parallel(n_jobs=n_jobs, prefer=prefer, pickler='dill')( delayed(convert_string)(string) for string in string_list )
方案3:拆分逻辑规避跨进程传回Score对象
如果后续对Score的处理逻辑可并行,直接将处理逻辑移入子进程执行,最终只传回可序列化的基础类型结果(数值、字符串、列表、字典等),完全规避序列化问题,性能最高:
def convert_and_process(string: str, format: str = "abc"): score = music21.converter.parse(string, format=format) # 直接在子进程完成所有对Score的处理,返回最终结果 result = your_process_logic(score) return result
内容的提问来源于stack exchange,提问作者James Owers
相关产品推荐
相关产品推荐

