Tom*_*nen 19 python dll ctypes
我正在使用ctypes在Python中加载DLL.这非常有效.
现在我们希望能够在运行时重新加载该DLL.
直截了当的方法似乎是:1.卸载DLL 2.加载DLL
不幸的是我不确定卸载DLL的正确方法是什么.
_ctypes.FreeLibrary可用,但是私有.
有没有其他方法来卸载DLL?
Pio*_*cki 16
你应该能够通过处理对象来做到这一点
mydll = ctypes.CDLL('...')
del mydll
mydll = ctypes.CDLL('...')
Run Code Online (Sandbox Code Playgroud)
编辑: Hop的评论是正确的,这解除了名称,但垃圾收集不会很快发生,事实上我甚至怀疑它甚至发布了加载的库.
Ctypes似乎没有提供一种释放资源的简洁方法,它只为_handle
dlopen句柄提供了一个字段...
因此,我看到的唯一方法,一种非常非常简洁的方式,是系统依赖于dlclose句柄,但它非常非常不洁,因为此外ctypes保持对此句柄的内部引用.所以卸载需要采取以下形式:
mydll = ctypes.CDLL('./mylib.so')
handle = mydll._handle
del mydll
while isLoaded('./mylib.so'):
dlclose(handle)
Run Code Online (Sandbox Code Playgroud)
它是如此不洁,以至于我只检查它的工作原理:
def isLoaded(lib):
libp = os.path.abspath(lib)
ret = os.system("lsof -p %d | grep %s > /dev/null" % (os.getpid(), libp))
return (ret == 0)
def dlclose(handle)
libdl = ctypes.CDLL("libdl.so")
libdl.dlclose(handle)
Run Code Online (Sandbox Code Playgroud)
小智 8
如果您使用的是 iPython 或类似的工作流程,那么能够卸载 DLL 会很有帮助,这样您就可以重建 DLL 而无需重新启动会话。在 Windows 中工作 我只尝试使用与 Windows DLL 相关的方法。
REBUILD = True
if REBUILD:
from subprocess import call
call('g++ -c -DBUILDING_EXAMPLE_DLL test.cpp')
call('g++ -shared -o test.dll test.o -Wl,--out-implib,test.a')
import ctypes
import numpy
# Simplest way to load the DLL
mydll = ctypes.cdll.LoadLibrary('test.dll')
# Call a function in the DLL
print mydll.test(10)
# Unload the DLL so that it can be rebuilt
libHandle = mydll._handle
del mydll
ctypes.windll.kernel32.FreeLibrary(libHandle)
Run Code Online (Sandbox Code Playgroud)
我不太了解内部结构,所以我不确定这有多干净。我认为删除 mydll 会释放 Python 资源,而 FreeLibrary 调用会告诉 Windows 释放它。我认为首先使用 FreeLibary 释放会产生问题,所以我保存了库句柄的副本并按照示例中显示的顺序释放它。
我将此方法基于ctypes unload dll,它预先明确加载了句柄。然而,加载约定不像简单的“ctypes.cdll.LoadLibrary('test.dll')”那么干净,所以我选择了显示的方法。
这里是类似讨论的概述(我从中构建了这个答案)。
这是针对 Windows 和 Linux 的,因此提供了 2 个编译脚本。测试条件:
cpp_代码.cpp
extern "C" int my_fct(int n)
{
int factor = 10;
return factor * n;
}
Run Code Online (Sandbox Code Playgroud)
编译linux.sh
#!/bin/bash
g++ cpp_code.cpp -shared -o myso.so
Run Code Online (Sandbox Code Playgroud)
编译windows.cmd
set gpp="C:\Program Files\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin\g++.exe"
%gpp% cpp_code.cpp -shared -o mydll.dll
PAUSE
Run Code Online (Sandbox Code Playgroud)
Python代码
from sys import platform
import ctypes
if platform == "linux" or platform == "linux2":
# /sf/answers/3569076241/
# /sf/answers/3655621791/
dlclose_func = ctypes.cdll.LoadLibrary('').dlclose
dlclose_func.argtypes = [ctypes.c_void_p]
fn_lib = './myso.so'
ctypes_lib = ctypes.cdll.LoadLibrary(fn_lib)
handle = ctypes_lib._handle
valIn = 42
valOut = ctypes_lib.my_fct(valIn)
print(valIn, valOut)
del ctypes_lib
dlclose_func(handle)
elif platform == "win32": # Windows
# /sf/answers/919042351/
# /sf/ask/25164891/
lib = ctypes.WinDLL('./mydll.dll')
libHandle = lib._handle
# do stuff with lib in the usual way
valIn = 42
valOut = lib.my_fct(valIn)
print(valIn, valOut)
del lib
ctypes.windll.kernel32.FreeLibrary(libHandle)
Run Code Online (Sandbox Code Playgroud)
如果共享库具有dependencies
,则这不一定再有效(但它可以 - 取决于依赖项 ^^)。我没有调查细节,但看起来机制如下:加载库和依赖项。由于依赖项未卸载,因此无法卸载库。
我发现,如果我将OpenCv
(版本 4.2)包含到我的共享库中,这会扰乱卸载过程。以下示例仅在linux系统上测试:
代码.cpp
#include <opencv2/core/core.hpp>
#include <iostream>
extern "C" int my_fct(int n)
{
cv::Mat1b mat = cv::Mat1b(10,8,(unsigned char) 1 ); // change 1 to test unloading
return mat(0,1) * n;
}
Run Code Online (Sandbox Code Playgroud)
编译用
g++ code.cpp -shared -fPIC -Wall -std=c++17 -I/usr/include/opencv4 -lopencv_core -o so_opencv.so
Python代码
from sys import platform
import ctypes
class CtypesLib:
def __init__(self, fp_lib, dependencies=[]):
self._dependencies = [CtypesLib(fp_dep) for fp_dep in dependencies]
if platform == "linux" or platform == "linux2": # Linux
self._dlclose_func = ctypes.cdll.LoadLibrary('').dlclose
self._dlclose_func.argtypes = [ctypes.c_void_p]
self._ctypes_lib = ctypes.cdll.LoadLibrary(fp_lib)
elif platform == "win32": # Windows
self._ctypes_lib = ctypes.WinDLL(fp_lib)
self._handle = self._ctypes_lib._handle
def __getattr__(self, attr):
return self._ctypes_lib.__getattr__(attr)
def __del__(self):
for dep in self._dependencies:
del dep
del self._ctypes_lib
if platform == "linux" or platform == "linux2": # Linux
self._dlclose_func(self._handle)
elif platform == "win32": # Windows
ctypes.windll.kernel32.FreeLibrary(self._handle)
fp_lib = './so_opencv.so'
ctypes_lib = CtypesLib(fp_lib, ['/usr/lib64/libopencv_core.so'])
valIn = 1
ctypes_lib.my_fct.argtypes = [ctypes.c_int]
ctypes_lib.my_fct.restype = ctypes.c_int
valOut = ctypes_lib.my_fct(valIn)
print(valIn, valOut)
del ctypes_lib
Run Code Online (Sandbox Code Playgroud)
如果到目前为止给出的代码示例或解释有任何问题,请告诉我。另外如果你知道更好的方法!如果我们能够一劳永逸地解决这个问题,那就太好了。
归档时间: |
|
查看次数: |
17265 次 |
最近记录: |