Python多进程调用DLL遇Pickle错误,如何正确实现?
Python进程池调用动态链接库失败:原因与解决方案
错误原因
你遇到的AttributeError: Can't pickle local object 'CDLL.__init__.<locals>._FuncPtr'错误,核心是multiprocessing进程池依赖pickle序列化传递任务参数,但ctypes加载的DLL对象(及其内部函数指针)无法被pickle序列化。进程池的子进程不能直接复用主进程中已加载的DLL实例,必须在每个子进程内部独立加载DLL。
解决方案
方案一:子进程函数内直接加载DLL
修改任务函数,让每个子进程在执行任务时自行加载DLL:
#!/usr/bin/env python3.8 from ctypes import * from multiprocessing import Pool, freeze_support def run_dll(args): x, y = args # 子进程内部独立加载共享库 dll_obj = cdll.LoadLibrary('./sum_dll.so') dll_obj.sum.restype = c_double return dll_obj.sum(c_double(x), c_double(y)) def main(): pool = Pool(processes=2) # 仅传递数据参数,不传递DLL对象 results = pool.map(run_dll, [(2, 3), (3, 4)]) print(results) pool.close() pool.join() if __name__ == "__main__": freeze_support() main()
方案二:进程池初始化时加载DLL(更高效)
如果子进程需要多次调用DLL,重复加载会有性能开销,可以通过Pool的initializer参数,让每个子进程启动时仅加载一次DLL并全局缓存:
#!/usr/bin/env python3.8 from ctypes import * from multiprocessing import Pool, freeze_support # 子进程全局变量,保存已加载的共享库实例 global_dll = None def init_worker(): """子进程初始化函数:加载共享库并配置函数返回类型""" global global_dll global_dll = cdll.LoadLibrary('./sum_dll.so') global_dll.sum.restype = c_double def run_dll(args): x, y = args return global_dll.sum(c_double(x), c_double(y)) def main(): # 指定初始化函数,每个子进程启动时执行一次 pool = Pool(processes=2, initializer=init_worker) results = pool.map(run_dll, [(2, 3), (3, 4)]) print(results) pool.close() pool.join() if __name__ == "__main__": freeze_support() main()
注意事项
- Linux下共享库后缀为
.so,Windows下为.dll,只需修改加载路径中的文件名即可适配 - 建议使用绝对路径加载共享库,避免子进程因工作目录不同找不到文件
- 子进程加载的共享库是独立实例,与主进程的实例互不影响
内容的提问来源于stack exchange,提问作者user43283
相关产品推荐
相关产品推荐

