C 怎么读取Cpp文件_python之调用C加速计算(一)

一、前言

python语言是目前比较火的语言,很容易上手,对数据处理也比较友好,可以用几行代码就能进行一些简单的数据处理工作。但是对于稍微大型的数值计算,或者一些涉及到大量循环的数值计算python的计算速度有点让人失望。

即使是使用numpy对算法算法进行优化,能提升的空间都非常有限了,当然网上有一行代码就提升100倍这种帖子,就是使用numba,但用了这个之后感受并不是太好,对于一个简单循环或许可以加速,对于复杂的循环效果也许并不好(可能是我不会使用,对numba没有太深入的研究)。

想要提升python的数值计算,目前看到比较好的解决方案就是用C给python写计算的lib,如果仅是数值计算,其实涉及到的C++语言的知识并不太多,基本就是for循环,if判断,以及一些STL库,个人觉得性价比还是挺高的。

python调用C进行数值计算最大难点就是如何进行数据交换,也就是如何把输入参数的指针传递给C,以及如何返回输出参数指针给python。有大神早就将这些都封装好了,就是使用pybind11。

二、pybind11简介

pybind11定义了一些python数据结构和C++的对应关系,使得数据交换变得非常简单,接下来简单介绍数值计算主要用的一些pybind11用到的知识。

1)获取pybind11

想要用到pybind11的功能当然得有pybind11的代码,网上可以直接下载到pybind11-master.rar文件,只需要下载到本地,然后解压就可以了。

2)cpp基本结构介绍

接下来直接就写代码吧,用Visual Studio创建个cpp文件(不会安装vs的可以自行百度安装一下,这个不是本文重点就不介绍了),本文使用的是VS2015。

首先include一些头文件。Emm…反正感觉会用的先include进来应该没错了。

7b427d9c54fa348f049899f99d4fb079.png 

接下来include本文的重点也就是pybind11的头文件。

e6ce8a5b9d48dfe7ee0597199bd63ba2.png

然后修改下命名空间,只是为了书写方便和import pandas as pd一个道理。

dd7d66ff29ef388f8979a05968e5c9ad.png

接下来要定义模块的入口。

e6f1e870f394aaae93bd0f7dbee7ccf0.png

其中calc就是在python调用时候的模块名称,m是在C++文件中的模块实例,可以通过m.doc()给这个模块写下文档,一般就是这个模块是干什么的,可以在python环境help该模块名来查看,接下来通过m.def定义函数名,第一个参数是字符串,是在python调用时候的函数名,第二个参数是C++文件中的对应函数名称,三个参数是该函数的介绍。

以上写完之后就可以愉快的开始写函数了,整个cpp的结构大致就是下面这样了。

57e0ffc265e627b10b550635b007879e.png

分别是头文件,命名空间,函数区,函数导出区。本文也按照常规套路hello world一把。

3)编译cpp成pyd文件

接下来需要通过编译器将cpp文件编译成python的pyd文件,首先要找到vs的x64本机工具命令提示符,本文以vs2015为例,在开始菜单直接搜索vs2015会出来以下选项(前提是你已经装了正确安装vs)。然后选择VS2014 x64 本机工具命令提示符(注意一定要是x64的)。

1c04e25cf44d52c06b36e36f1e55e180.png

打开之后通过cd /d 路径,这个命令将路径切换到cpp所在路径。然后输入以下命令

075dd44a6a916646dd9dd8521008bde4.png

其中calc.cpp是待编译的cpp文件,路径1需要替换成前文获取到的pybind11-master文件夹下的include文件夹的所在路径,路径2需要替换成python安装路径的include文件夹的所在路径,路径3替换成python安装路径下的libs文件夹的所在路径,calc.pyd是生成的pyd名称,需要和cpp中模块名一致。

输入上述代码回车之后,编译成功会有如下信息打印,同时在cpp所在路径会产生四个文件,我们需要的只是后缀为.pyd的文件。

2c8eb64895eb485c5e234a25f8b563ad.png

4)python执行

之后打开前文编译所有的python环境来进行测试,注意这里编译的pyd不同python版本是不能共用的(即python3.5编译出来的文件,python3.6并不能调用),有时同样是3.6编译出来的也不能使用,这个还没研究是怎么一个兼容关系。

python调用pyd文件,一种简单的方法是用sys模块直接加入pyd文件所在路径,就可以直接调用,或者也可拷贝pyd文件到python能找到的路径下,比如python的安装路径下。然后执行写好的函数就有如下结果。

b99d4c76872c6ad8e429368fb82ff172.png 

好的到此咱们已经完成了整个从下载所需文件,到cpp文件书写,然后对cpp进行编译,最后在python执行的全过程。

5)pybind11数据结构介绍

在数值计算用的最多的结构是array_t<>,可以是array_t,array_t或者array_t,当然用的最多的肯定是array_t了。

a6cc4af76202bdfdc3a3fa9beacbd3cc.png

以上是一个两个矩阵输入,同时输出函数也是一个矩阵的函数声明,在array_t里面封装了数据矩阵的指针以及数据矩阵的大小。

5d2a4a71c80c8ca758417269b0ddd78a.png

通过以上方法获得了两个数据指针ptr1和ptr2,以及第一个矩阵的大小。

接下来定义输出参数,申请内存并获得数据指针。

7ca08a1933d461f9338727539d4bfb34.png 

上述简单介绍了py::array_t的基本用法,pybind11还定义了py::list等等数据封装内容这些可以自行查看pybind11文档或者相应的pdf文档。

pybind11文档https://pybind11.readthedocs.io/en/master/intro.html

6)读取和数据存储

为了方便代码书写,本文会获得的指针进行宏定义,使得代码更有可读性,这里就涉及到了数据存储方式的问题。

84c87b3062ca6953899b57f9d91db7ad.png

这里示范的书写方法是默认输入矩阵和输出矩阵都是按行存储,这一点特别需要注意,其中numpy里的array数据默认是按行存储,也就是不管何种存储方式,只要对array数据进行copy操作之后,返回的数据都是按行存储。所以一般用array数据矩阵作为C函数输入时,进行copy操作是比较稳妥的方式,但是当矩阵较大时,进行矩阵的深拷贝的速度往往会很慢,甚至可能大于计算所需要的时间。

python常用的库还有pandas,DataFrame数据的存储默认是按列存储,也就是从通过某个dataframe数据.values的方法获得的array数据矩阵,默认是按列存储。

那么如何知道一个array数据矩阵是按行存储还是按列存储呢,array数据有相应参数进行说明。

b99f6e9c010818b72ae0dd374006e287.png

array数据矩阵的flags属性下,有f_contiguous和c_contiguous这两个布尔类型的属性,当c_contiguous为真时,矩阵是按行存储,当f_contiguous为真时,矩阵是按列存储。其中f好像是表示Fortran语言,这种语言主要用来进行科学计算,是按列存储,据网上说超大型的数值计算都是用这种语言。c表示C语言,c语言是按行存储。平时用的比较多的数值计算的还有matlab,matlab是按列存储的。貌似对于截面数据来说,进行时间序列上的操作确实是按列存储比较占优。

895c4c0dc3bddeac528e7195a41bf60c.png

a5e440208e4eb3b572215b37bd89e336.png

7)C++函数结构

对于一个常用的输入为矩阵,输出也为矩阵的函数来说,大致的函数结构如下。

0d03ed304fdc247c2ed6e9d178625307.png

分为输入参数获取,输出参数定义,数据矩阵宏定义,运算逻辑,以及结果的返回。基本上的函数书写,仅需要关注运算逻辑如何书写,其他几部分内容都是相对固定的。

三、后语

前文内容详细介绍了如何构建整个cpp的内容结构,C++函数的内容结构,以及pybind11最常用的py::array_t的介绍。在给python写调用函数时,只需要专注于C++函数内容的运算逻辑区的代码即可,可以说已经非常简单了。

文中提到的pybind11-master.rar,pybind11用户pdf文档,关注本公众号回复【加速一】就可以获得。

这个只是本系列的第一篇介绍,后续有使得你运行速度更快的详细介绍,期待你的运算速度可以起飞~~~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/437376.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【转】刨根究底字符编码【2.0版】(3):字符编码的由来、演变与ASCII码

为什么需要字符编码 1. 计算机一开始发明出来时是用来解决数字计算问题的&#xff0c;后来人们发现&#xff0c;计算机还可以做更多的事&#xff0c;例如文本处理。 但计算机其实挺“笨”的&#xff0c;它只“认识”010110111000…这样由0和1两个数字组成的二进制数字&#…

JS创建对象的模式介绍

转自http://www.cnblogs.com/asqq/archive/2013/02/01/3194993.html

matplotlib的优点_超详细matplotlib基础介绍!!!

(给Python开发者加星标&#xff0c;提升Python技能)来源&#xff1a;逐梦erhttps://zhumenger.blog.csdn.net/article/details/106530281【导语】&#xff1a;出色的数据可视化&#xff0c;会让你的数据分析等工作锦上添花&#xff0c;让人印(升)象(职)深(加)刻(薪)。matplotli…

【转】WPF PRISM开发入门一( 初始化PRISM WPF程序)

这篇博客将介绍在WPF项目中引入PRISM框架进行开发的一些基础知识。目前最新的PRISM的版本是Prism 6.1.0&#xff0c;可以在Github上获取PRISM的源码。这个系列的博客将选择PRISM 4.1版本来讲解。可以从微软官网上下载到PRISM 4.1相关内容。将下载下来的文件解压开&#xff1a; …

截屏悬浮软件_功能强大,却小巧的录屏软件,不在错过你的王者时刻

看看录屏是一款操作简单。功能强大的录屏软件。他可以设置你录制视频的一个分辨率&#xff0c;帧率以及录制屏幕方向&#xff0c;非常方便&#xff0c;用户将手机摇一摇就可以控制开启和停止录屏&#xff0c;高效录制精彩瞬间&#xff0c;在录制游戏视频的时候也可以做到不掉帧…

公司用的非标普通自动化用单片机还是plc_PLC的介绍

PLC又叫可编程控制器&#xff0c;一开始是替代传统接触器的一个东西。随着人工价格不断的上涨&#xff0c;自动化的设备会越来越普及。自动化不再是大企业才用的起的东西 &#xff0c;各种多元化小型自动化设备进入了普通小企业甚至家庭作坊。PLC其实是单片机开发出来的一种工业…

比较文本差异的工具_Linux 开发的五大必备工具 | Linux 中国

Linux 已经成为工作、娱乐和个人生活等多个领域的支柱&#xff0c;人们已经越来越离不开它。在 Linux 的帮助下&#xff0c;技术的变革速度超出了人们的想象&#xff0c;Linux 开发的速度也以指数规模增长。因此&#xff0c;越来越多的开发者也不断地加入开源和学习 Linux 开发…

【转】C# 动态对象(dynamic)的用法

说到正确用法&#xff0c;那么首先应该指出一个错误用法&#xff1a; 常有人会拿var这个关键字来和dynamic做比较。实际上&#xff0c;var和dynamic完全是两个概念&#xff0c;根本不应该放在一起做比较。var实际上是编译期抛给我们的“语法糖”&#xff0c;一旦被编译&#x…

关于prototype使用位置问题的讨论

问题贴&#xff1a;http://bbs.csdn.net/topics/390446362 new四部曲&#xff1a; &#xff08;1&#xff09;创建一个新的对象&#xff0c;并让函数的 this 指针指向它&#xff1b; &#xff08;2&#xff09;将函数的 prototype 对象的所有成员都赋给这个新对象&#xff0c…

@query传参_vue-router中params传参和query传参的区别及处理方法

在 Vue 实例内部&#xff0c;你可以通过 $router 访问路由实例。因此你可以调用 this.$router.push想要导航到不同的 URL&#xff0c;则使用 router.push 方法。这个方法会向 history 栈添加一个新的记录&#xff0c;所以&#xff0c;当用户点击浏览器后退按钮时&#xff0c;则…

JS成员函数声明位置优化

上代码 function A() {this.a function(){}; } a1 new A(); a2 new A(); alert( a1.aa2.a);输出 说明了a1.a&#xff0c;a2.a指向的内存不是同一个&#xff0c;也就是每个对象都有一份自己的函数&#xff0c;只不过一个类的所有实例之间的函数长得是一样的&#xff01; 所以…

mybatis plus 事务管理器_SpringBoot第七篇:springboot开启声明式事务

springboot开启事务很简单&#xff0c;只需要一个注解Transactional 就可以了。因为在springboot中已经默认对jpa、jdbc、mybatis开启了事事务&#xff0c;引入它们依赖的时候&#xff0c;事物就默认开启。当然&#xff0c;如果你需要用其他的orm&#xff0c;比如beatlsql&…

JS静态变量和静态函数

function A(){this.id "我是AA"} // 在构造函数外定义的都是所有对象共享的 A.id "我是A"; A.sayId function(){alert(A.id);} A.sayId(); 如上&#xff0c;在构造函数外用函数名定义的属性或者方法&#xff0c;可以也只可以通过函数名来访问&…

Spark读取HDFS上的Snappy压缩文件所导致的内存溢出问题 java.lang.OutOfMemoryError: GC overhead limit exceeded

报错java.lang.OutOfMemoryError: GC overhead limit exceeded HDFS上有一些每天增长的文件&#xff0c;使用Snappy压缩&#xff0c;突然某天OOM了 1.原因: 因为snappy不能split切片&#xff0c;也就会导致一个文件将会由一个task来读取&#xff0c;读取后解压&#xff0c;数…

【转】VS编程,快速折叠或者展开代码到 #region 级别的设置方法。

在代码比较多的文档中&#xff0c;使用#region进行分功能的区分折叠是一个方便的方法。 如果文档中含有很多个#region标签&#xff0c;想一次全部折叠或者展开&#xff0c;有时是必要的。 这里给出一种设置方法&#xff0c;适用于VS2019&#xff0c;其它VS版本请自己验证。 1、…

.net一个函数要用另一个函数的值_Mysql:条件判断函数-CASE WHEN、IF、IFNULL详解

前言在众多SQL中&#xff0c;统计型SQL绝对是让人头疼的一类&#xff0c;之所以如此&#xff0c;是因为这种SQL中必然有大量的判读对比。而条件判断函数就是应对这类需求的利器。本文重点总结CASE WHEN、IF、IFNULL三种函数。1 CASE WHENCase when语句能在SQL语句中织入判断逻辑…

Spark2内存调优总结 - 内存划分 与 内存计算 与 调参方式

使用的Spark2以上版本所以只考虑UnifiedMemoryManager动态内存管理&#xff0c;如图&#xff1a; 1. 内存划分 与 内存计算 与 调参方式 1.1 三部分&#xff1a;Spark内存、用户内存、预留内存 预留内存&#xff1a;300MB 固定Spark内存和用户内存比例由参数spark.memory.fra…

java 通过id获取html代码_Maven私服安装配置,java通过私服下载代码,并打包后上传到私服(Nexus)...

Maven私服一般安装Nexus。首先&#xff0c;Nexus下载&#xff0c;访问Nexus官方网址https://www.sonatype.com/download-nexus-repo-oss下载完成后是个压缩包第二步 配置&#xff1a;1)将上一步下载的nexus解压2)端口和监听配置application-port&#xff1a;监听端口applicatio…

一些网站github等无法连接服务器的解决办法

1.打开站长工具 http://tool.chinaz.com/speedtest/ 2.搜索github.com/ 3. 点击总耗时-排序 4. 拿到延迟最低的ip地址20.205.243.166 5.修改本地dns windows&#xff1a;C:\Windows\System32\drivers\etc 修改hosts文件&#xff0c;末尾添加 20.205.243.166 github.com Lin…