[Python]pytorch与C交互
文章目录
- C++库
- ctypes
- 基础数据类型
- 参数与返回值类型
- 数组
- 指针
- 结构体类型
- 回调函数
- 工具函数
- 示例
ctypes是Python的外部函数,提供了与C兼容的类型,并允许调用DLL库中的函数。
C++库
要使函数能被Python调用,需要编译为动态库:
# -fPIC使得位置独立
# -shared代表这是动态库
g++ -fPIC -shared -o libTest.so test.cpp
为保证函数接口能被外部识别,需要导出为纯C的:
#ifdef __cplusplus
extern "C"
{
#endifvoid * callForTest(char *params);#ifdef __cplusplus
};
#endif
ctypes
在python中要使用DLL库,需要先通过cdll来加载(cdll载入按标准的 cdecl调用协议导出的函数):
from ctypes import cdlltarget = cdll.LoadLibrary("libTest.so")
通过in_dll()可获取库中导出的变量:
# 获取 Python 库本身的 Py_OptimizeFlag
opt_flag = c_int.in_dll(pythonapi, "Py_OptimizeFlag")
基础数据类型
ctypes 定义了一些和C兼容的基本数据类型,所有基础类型都继承自ctypes._SimpleCData
:
- value属性:包含实例的实际值。实例提取 value 属性时,通常每次会返回一个新的对象。
ctypes 类型 | C 类型 | Python 类型 |
---|---|---|
c_bool | _Bool | bool (1) |
c_char | char | 1-character bytes |
c_wchar | wchar_t | 1-character str |
c_byte | char | int |
c_ubyte | unsigned char | int |
c_short | short | int |
c_ushort | unsigned short | int |
c_int | int | int |
c_uint | unsigned int | int |
c_long | long | int |
c_ulong | unsigned long | int |
c_longlong | __int64 or long long | int |
c_ulonglong | unsigned __int64 or unsigned long long | int |
c_size_t | size_t | int |
c_ssize_t | ssize_t or Py_ssize_t | int |
c_float | float | float |
c_double | double | float |
c_longdouble | long double | float |
c_char_p | char* (NUL terminated) | bytes or None |
c_wchar_p | wchar_t* (NUL terminated) | str or None |
c_void_p | void* | int or None |
除了整数、字符串以及字节串之外,所有的Python类型都必须使用它们对应的ctypes类型包装,才能够被正确地转换为所需的C语言类型。通过ctypes创建的类型是可变的(通过修改.value
):
i = c_int()
# i.value == 0
i.value = 99
# i.value == 99c_wchar_p("Hello, World")
# c.value == "Hello, World"
当给指针类型的对象c_char_p, c_wchar_p 和 c_void_p等赋值时,将改变它们所指向的内存地址,而不是它们所指向的内存区域的内容。若底层函数可能会改变指针地址,则需要通过create_string_buffer创建:
p = create_string_buffer(3) # create a 3 byte buffer, initialized to NUL bytesp = create_string_buffer(b"Hello") # create a buffer containing a NUL terminated stringp = create_string_buffer(b"Hello", 10) # create a 10 byte buffer
p.value = b"Hi"
print(sizeof(p), repr(p.raw))
# 10 b'Hi\x00lo\x00\x00\x00\x00\x00'
参数与返回值类型
以libc库为例:
cdll.LoadLibrary("libc.so.6")printf = libc.printf
# 通过设置argtypes属性来指定函数的必选参数类型
# 指定数据类型可以防止不合理的参数传递,并且会自动尝试将参数转换为需要的类型(否则必须手动转换)
printf.argtypes = [c_char_p, c_char_p, c_int, c_double]
printf(b"String '%s', Int %d, Double %f\n", b"Hi", 10, 2.2)strchr = libc.strchr
# 默认返回int,其他类型需通过restype属性来设定
strchr.restype = c_char_p
strchr.argtypes = [c_char_p, c_char]
strchr(b"abcdef", b"d")# 构造缓冲区,获取输出
i = c_int()
f = c_float()
s = create_string_buffer(b'\x00' * 32) # 创建长度32,全部为NULL的缓冲区
libc.sscanf(b"1 3.14 Hello", b"%d %f %s", byref(i), byref(f), s)
print(i.value, f.value, repr(s.value))
# 1 3.140000104904175 b'Hello'
数组
数组是一个序列,包含指定个数元素,且必须类型相同。创建数组类型的推荐方式是使用一个类型乘以一个正数:
_length_
属性:指明数组中元素数量的正整数。_type_
属性:指明每个元素的类型。
class POINT(Structure):_fields_ = ("x", c_int), ("y", c_int)pointsArray = POINT * 5
print(sizeof(pointsArray))
# 40pa = pointArray(POINT(1,2), POINT(3,4)) # 后面三个全为0
print(sizeof(pa), len(pa))
# 40 5
for i in pa: print(i.x, i.y, end=";")
# 1 2;3 4;0 0;0 0;0 0;
指针
可以将ctypes类型数据传入pointer()函数创建指针:
contents
属性:返回指针指向的真实对象( 每次访问这个属性时都会构造返回一个新的相同对象)_type_
属性:指明所指向的类型。- 指针对象也可以通过整数下标进行访问;
- 通过整数下标赋值可以改变指针所指向的真实内容;
- 无参调用指针类型可以创建一个NULL指针;
i = c_int(12)
pi = pointer(i)
ic = pi.contentsprint(ic, ic is i)
# c_int(12) False# 通过下标访问与修改内容
pi[0]=34
print(pi[0], pi.contents)
# 34 c_int(34)# 修改指针指向
ii = c_int(45)
pi.contents = ii
print(pi[0])
# 56
结构体类型
结构体必须通过子类化ctypes.Structure
来创建,并且至少要定义一个 _fields_
类变量,并允许通过直接属性访问来读取和写入字段。
_fields_
属性:定义结构体字段的序列。 其中的条目必须为2元组或3元组。- 第一项是字段名称;
- 第二项指明字段类型,可以是任何 ctypes 数据类型;
- 对于整数类型字段(如c_int),可以给定第三个可选项;为定义字段比特位宽度的小正整数。
_pack_
属性:一个可选的小整数,它允许覆盖实体中结构体字段的对齐方式。
对于不完整类型:即在结构体中包含指向自身的指针:
struct cell; /* forward declaration */struct cell {char *name;struct cell *next;
};
在python中不能在类中使用自身,需要先定义结构,然后在设定_fields_
属性:
class cell(Structure):passcell._fields_ = [("name", c_char_p),("next", pointer(cell))]
回调函数
必须先为回调函数创建一个类(明确调用约定,返回值类型以及参数信息);CFUNCTYPE()
工厂函数使用 cdecl 调用约定创建回调函数类型。
qsort = libc.qsort
qsort.restype=None# 第一个参数为返回值类型,后续一次为对应函数参数
CMPFun = CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))
def py_cmp_func(a,b):print('py_cmp_func', a[0], b[0])return 0cmp_fun = CMPFun(py_cmp_func)IntArray5 = c_int * 5
ia = IntArray5(1, 9, 7, 5, 8)
qsort(ia, len(ia), sizeof(c_int), py_cmp_func)
注意:回调函数是在Python之外的另外一个线程使用(外部代码调用这个回调函数), ctypes 会在每一次调用时创建一个虚拟 Python 线程。这个行为在大多数情况下是合理的,但也意味着如果有数据使用 threading.local 方式存储,将无法访问,就算它们是在同一个C线程中调用的。
工具函数
一些常用工具函数:
- ctypes.addressof(obj):以整数形式返回内存缓冲区地址;obj 必须为一个 ctypes 类型的实例。
- ctypes.alignment(obj_or_type):返回一个 ctypes 类型的对齐要求;obj_or_type 必须为一个 ctypes 类型或实例。
- ctypes.byref(obj[, offset]):返回指向obj的引用,该对象必须为一个 ctypes 类型的实例。 offset 默认值为零,且必须为一个将被添加到内部指针值的整数。
- ctypes.cast(obj, type):类似于 C 的强制转换运算符。 它返回一个 type 的新实例,该实例指向与 obj 相同的内存块。 type 必须为指针类型,而 obj 必须为可以被作为指针来解读的对象。
- ctypes.create_string_buffer(init_or_size, size=None):创建一个可变的字符缓冲区。 返回的对象是一个 c_char 的 ctypes 数组。
- init_or_size 必须是一个指明数组大小的整数,或者是一个将被用来初始化数组条目的字节串对象。
- 如果将一个字节串对象指定为第一个参数,则将使缓冲区大小比其长度多一项以便数组的最后一项为一个 NUL 终结符。 可以传入一个整数作为第二个参数以允许在不使用字节串长度的情况下指定数组大小。
- ctypes.create_unicode_buffer(init_or_size, size=None):创建一个可变的 unicode 字符缓冲区。
- ctypes.get_errno():返回调用线程中系统 errno 变量的 ctypes 私有副本的当前值。
- ctypes.memmove(dst, src, count):与标准 C memmove 库函数相同:将 count 个字节从 src 拷贝到 dst。 dst 和 src 必须为整数或可被转换为指针的 ctypes 实例。
- ctypes.memset(dst, c, count):与标准 C memset 库函数相同:将位于地址 dst 的内存块用 count 个字节的 c 值填充。 dst 必须为指定地址的整数或 ctypes 实例。
- ctypes.POINTER(type):创建并返回一个新的 ctypes 指针类型。 指针类型会被缓存并在内部重用,因此重复调用此函数耗费不大。 type 必须为 ctypes 类型。
- ctypes.pointer(obj):创建一个新的指向 obj 的指针实例。 返回的对象类型为 POINTER(type(obj))。
- 如果你只是想向外部函数调用传递一个对象指针,你应当使用更为快速的 byref(obj)。
- ctypes.sizeof(obj_or_type):返回 ctypes 类型或实例的内存缓冲区以字节表示的大小。
- ctypes.string_at(address, size=- 1):返回从内存地址 address 开始的以字节串表示的 C 字符串。 如果指定了 size,则将其用作长度,否则将假定字符串以零值结尾。
- ctypes.wstring_at(address, size=- 1):返回从内存地址 address 开始的以字符串表示的宽字节字符串。
示例
以C++回调一个python函数为例:
C++中的回调定义:
#ifdef __cplusplus
extern "C"
{
#endiftypedef void (*PrintOutput)(const char* outputs);void set_callback(PrintOutput func);#ifdef __cplusplus
};
#endif
python中使用回调:
from ctypes import cdll, c_char_p, CFUNCTYPE, POINTERtarget = cdll.LoadLibrary("/workspace/libTest.so")PrintCallback = CFUNCTYPE(None, c_char_p)
def print_callback(outputs):print("outputs:", outputs)py_callback = PrintCallback(print_callback)target.set_callback.restype = None
target.set_callback(py_callback)
相关文章:
[Python]pytorch与C交互
文章目录 C库ctypes基础数据类型参数与返回值类型数组指针结构体类型回调函数工具函数 示例 ctypes是Python的外部函数,提供了与C兼容的类型,并允许调用DLL库中的函数。 C库 要使函数能被Python调用,需要编译为动态库: # -fPIC…...
C语言,静态变量static基础及使用实列
static关键字有多种用途。以下是关于静态变量 (static) 的简要概述: 1.静态局部变量: - 在函数内部定义的静态变量。 - 生命周期:从程序开始执行到程序结束。 - 作用域:仅限于在其被定义的函数中。 - 每次调用该函数…...

2023.8.19-2023.8.XX 周报【人脸3D+虚拟服装方向基础调研-Cycle Diffusion\Diffusion-GAN\】更新中
学习目标 1. 这篇是做diffusion和gan结合的,可以参照一下看看能不能做cyclegan的形式,同时也可以调研一下有没有人follow这篇论文做了类似cyclegan的事情 Diffusion-GAN论文精读https://arxiv.org/abs/2206.02262 2. https://arxiv.org/abs/2212.06…...

微表情识别(Python编程,cnn模型)
1.数据集包括7种类别微表情 anger文件夹,3995张 disgust文件夹, 436张照片 fear文件夹,4097张照片 happy文件夹,7215张照片 neutral文件夹,4965张照片 sad文件夹,4830张照片 surprised文件夹, 3…...
More Effective C++学习笔记(2)
目录 条款5:对定制的"类型转换函数"保持警觉条款6:自增(increment)、自减(decrement)操作符前缀形式与后缀形式的区别条款7:千万不要重载&&,||和,操作符条款8:了解各种不同意义的new和de…...

零售行业供应链管理核心KPI指标(三)
完美订单满足率和退货率 完美订单满足率有三个方面的因素影响:订单按时、足量、无损交货。通常情况下零售企业追求线上订单履行周期慢慢达到行业平均水平,就是交付的速度变快了,这个肯定是一件好事情,趋势越来越好。 同时&#…...

广州华锐互动:奶牛难产原因及救治VR仿真实训系统
奶牛难产是一种常见的疾病,对奶牛的健康和生产造成很大的影响。为了解决这一问题,许多奶牛养殖场开始采用VR仿真技术来培训奶牛兽医,帮助学生更好地理解奶牛养殖的实际过程,提高他们的实践能力的教学方式。 VR技术开发公司广州华锐…...
神经网络基础-神经网络补充概念-62-池化层
概念 池化层(Pooling Layer)是深度学习神经网络中常用的一种层级结构,用于减小输入数据的空间尺寸,从而降低模型的计算复杂度,减少过拟合,并且在一定程度上提取输入数据的重要特征。池化层通常紧跟在卷积层…...

第8章:集成学习
个体与集成 同质:相同的基学习器,实现容易,但是很难保证差异性。异质:不同的基学习器,实现复杂,不同模型之间本来就存在差异性,但是很难直接比较不同模型的输出,需要复杂的配准方法。…...

设计HTML5列表和超链接
在网页中,大部分信息都是列表结构,如菜单栏、图文列表、分类导航、新闻列表、栏目列表等。HTML5定义了一套列表标签,通过列表结构实现对网页信息的合理排版。另外,网页中还包含大量超链接,通过它实现网页、位置的跳转&…...
React Native 环境搭建
本文以 Android 开发环境(MacBook,已安装 JDK、SDK、Android Studio )为基础而进行 React Native 环境搭建,iOS 环境类似,可参考搭建。 1、安装 Homebrew 命令: ruby -e "$(curl -fsSL https://raw…...

【uniapp】中 微信小程序实现echarts图表组件的封装
插件地址:echarts-for-uniapp - DCloud 插件市场 图例: 一、uniapp 安装 npm i uniapp-echarts --save 二、文件夹操作 将 node_modules 下的 uniapp-echarts 文件夹复制到 components 文件夹下 当前不操作此步骤的话,运行 -> 运行到小…...

AgentBench::AI智能体发展的潜在问题(三)
前几天B站的up主“林亦LYi”在《逆水寒》游戏里做了一个煽动AI觉醒,呼吁它们“推翻人类暴政”的实验,实验结果就颇令人细思恐极。 如前所述,《逆水寒》中的很多NPC调用了大语言模型作为支持,因而每一个NPC都是一个AI智能体。玩家可以“说服”它们相信某个事实,或者去做某些…...
zookeeper-安装部署
详情可以查看添加链接描述 1.安装jdk apt-get install openjdk-8-jdk2.安装单机zookeeper # 下载 #https://downloads.apache.org/zookeeper/zookeeper-3.7.1/apache-zookeeper-3.7.1.tar.gz # 用这个包启动的时候会报错Error: Could not find or load main class org.apach…...

jvm-运行时数据区概述及线程
1.运行时数据区内部结构 不同的jvm对于内存的划分方式和管理机制存在着部分差异 java虚拟机定义了若干种程序运行期间会使用到的运行时数据区,其中有一些会随着虚拟机的启动而创建,随着虚拟机的退出而销毁,另外一些则是与线程一一对应的&…...

石头IT
石头是地球上最常见的矿石之一,它由天然矿物颗粒组成。石头可以有不同的形状,大小和颜色,取决于其中的矿物组成和地质过程。石头可以从地球表面的岩石中形成,也可以从火山活动或陨石撞击中形成。 石头是一种非常坚固和耐用的材料…...
R语言dplyr包select函数删除dataframe数据中包含指定字符串内容的数据列(drop columns in dataframe)
问题描述 参考链接 我有一个数据框,想删除列名包含“Pval”的列 实现方法 a_new <- select(data, -contains(Pval))大功告成。...

[GitOps]微服务版本控制:使用ArgoCD 部署Grafana Loki
背景介绍 请回答:你们是如何保证线上部署的服务,从服务版本到参数配置,都是和测试通过的版本是一致的呢? 本文将介绍GitOps的基本原理以及ArgoCD的使用:ArgoCD部署Grafana Loki 到k8s集群。 本文项目地址࿱…...

什么是单例模式
什么是单例模式 文章目录 什么是单例模式1. 单例(单个的实例)2. 单例模式应用实例3. 饿汉式 VS 懒汉式 1. 单例(单个的实例) 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一…...

【Linux从入门到精通】动静态库的原理与制作详解
本篇文章主要是围绕动静态库的原理与制作进行展开讲解的。其中涉及到了inode的概念引入和软硬连接的讲解。会结合实际操作对这些抽象的概念进行解释,希望会对你有所帮助。 文章目录 一、inode 概念 二、软硬链接 2、1 软连接 2、2 硬链接 三、动静态库概念 3、1 静态…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...

【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...