You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 21:05:17