Dask结合pybind11时,client.submit()返回对象值异常问题
问题原因分析
1. 对象序列化缺失
Dask分布式任务中,函数返回的对象需要先序列化才能在worker和客户端之间传输,传输完成后再反序列化恢复。pybind11默认导出的C++类不支持Python的pickle序列化协议,导致dbPrep对象的状态(比如设置的type=100)无法被保存。当你调用client.gather时,客户端会重新初始化一个默认状态的dbPrep对象,自然拿到的是初始值-9999。
2. 进程隔离导致的对象重建
init_db是在Dask的worker进程里执行的,创建的dbPrep对象只存在于该worker的内存中。如果对象无法序列化,Dask不会把worker里的实际对象实例传给客户端,而是会在客户端进程中新建一个dbPrep对象,这个新对象的成员变量都是初始值。
3. pybind11封装未处理状态持久化
如果dbPrep类的set_type修改的是对象的成员变量,但pybind11的封装代码没有实现对象状态的保存与恢复逻辑(比如深拷贝、序列化钩子),跨进程传输时对象的修改状态就会丢失。
验证步骤
- 在
init_db函数内部调用get_type并打印,确认worker进程中对象的type确实被设置为100,排除函数执行本身的错误。 - 本地直接创建
dbPrep对象,调用set_type(100)后再调用get_type,验证pybind11的封装逻辑本身没问题。
解决思路
- 给pybind11封装的
dbPrep类添加pickle支持:通过py::pickle接口实现__getstate__和__setstate__方法,让Python能正确序列化对象的状态数据,传输后反序列化恢复原对象。 - 避免传输对象实例:把需要使用
dbPrep对象的逻辑都放到worker端执行,只传输最终的计算结果(比如直接返回get_type()的值),而不是对象本身。
内容的提问来源于stack exchange,提问作者user1273456
相关产品推荐
相关产品推荐

