试图在 python 中使用 Pooling 运行 dll-library 并遇到以下问题。我创建了一个简单的 dll 库来说明这个问题。这是 dll 库的源代码,其中仅包含一个函数,该函数对两个双精度数求和:
extern "C" {
double sum(double x, double y);
}
double sum(double x, double y) {
return x + y;
}
在 Linux 系统上编译它使用
g++ -fPIC -c dll_main.cpp
g++ dll_main.o -shared -o sum_dll.so
在以下 Python 脚本中使用此 dll 库:
#!/usr/bin/env python3.8
from ctypes import *
import multiprocessing
from multiprocessing import Pool, freeze_support
def run_dll(dll_obj, x, y):
x_c = c_double(x)
y_c = c_double(y)
z = dll_obj.sum(x_c, y_c)
return z
def main():
pool = Pool(processes=2)
dll_obj = cdll.LoadLibrary('./sum_dll.so')
dll_obj.sum.restype = c_double
z = pool.map(run_dll, [(dll_obj, 2, 3), (dll_obj, 3, 4)])
pool.close()
pool.join()
if __name__ == "__main__":
freeze_support()
main()
收到以下错误消息:
Traceback (most recent call last):
File "./run_dll.py", line 24, in <module>
main()
File "./run_dll.py", line 17, in main
z = pool.map(run_dll, [(dll_obj, 2, 3), (dll_obj, 3, 4)])
File "/usr/lib/python3.8/multiprocessing/pool.py", line 364, in map
return self._map_async(func, iterable, mapstar, chunksize).get()
File "/usr/lib/python3.8/multiprocessing/pool.py", line 768, in get
raise self._value
File "/usr/lib/python3.8/multiprocessing/pool.py", line 537, in _handle_tasks
put(task)
File "/usr/lib/python3.8/multiprocessing/connection.py", line 206, in send
self._send_bytes(_ForkingPickler.dumps(obj))
File "/usr/lib/python3.8/multiprocessing/reduction.py", line 51, in dumps
cls(buf, protocol).dump(obj)
AttributeError: Can't pickle local object 'CDLL.__init__.<locals>._FuncPtr'
究竟错了什么?如何在 python 中正确使用具有多个进程的 dll-library?
解决方案:
不能 pickle dll 指针,因为访问 dll 需要一个系统调用来将它们链接到你的进程。
可以做到这一点的方法是在全局范围内以与定义普通 python 函数相同的方式定义此函数。
from ctypes import *
import multiprocessing
from multiprocessing import Pool, freeze_support
dll_obj.cdll.LoadLibrary('./sum_dll.so')
dll_obj.sum.restype = c_double
def run_dll(x, y):
x_c = c_double(x)
y_c = c_double(y)
z = dll_obj.sum(x_c, y_c)
return z
然后在 main 中调用这个 python 函数
def main():
pool = Pool(processes=2)
z = pool.map(run_dll, [(2, 3), (3, 4)])
pool.close()
pool.join()
if __name__ == "__main__":
freeze_support()
main()
上述代码的执行方式取决于自己的操作系统,适用于所有平台。