对于大规模重复的运算,为了提高运算速度,可以将部分核心代码用C++来实现,用编译器编译成动态可执行文件(mex文件),在MATLAB中直接调用。
个人亲历,有一段Monte-Carlo仿真的MATLAB代码,在Intel 8700K+32G的机器上,运行时间在1周左右,经过C++重构核心代码后,可以在2天内完成。同时,由于内存的占用降低,可以进行更大规模的仿真。
MATLAB版本:R2018b;C++编译器:Visual Studio 2015 Professional;
关于不同版本MATLAB支持的编译器,参考官网链接。
一、在Visual Studio中编写C++文件。
1.1 新建一个win32项目
项目名最好与函数名一致,注意应用程序类型设置为DLL。
1.2 配置项目属性。
- 在项目名称上右键 -> 属性即可打开项目属性页。
- 配置属性->配置管理器->活动平台解决方案 -> 新建解决方案平台 -> x64;
- 配置属性->C++ ->附加包含目录,加入MATLAB目录下的externinclude 路径,默认为C:Program FilesMATLABR2018bexterninclude;
- 配置属性->链接器->附加库目录,加入MATLAB目录下的externlibwin64microsoft路径,默认为C:Program FilesMATLABR2018bexternlibwin64microsoft;
- 配置属性->链接器->输入->附加依赖项, 添加libmx.lib,libeng.lib,libmat.lib,libmex.lib这四个lib文件;
- 配置属性->链接器->常规->输出文件,改为x64Debugvlda.mexw64 (vlda为项目名称);
- 配置属性->配置属性->常规->目标文件扩展名,改为.mexw64;
- 新建模块定义文件,vlda.def,内容为
LIBRARY
- 配置属性->链接器->输入->模块定义文件,vlda.def;
1.3 编写函数文件
在源文件里面已有vlda.cpp(vlda为项目名称),在vlda.cpp中编写MEX函数文件。
mex函数的编写注意事项:
- 注意检查输入的参数类型,参数数目,MATLAB默认的数据类型为double,一旦不匹配,MATLAB调用时会直接崩溃;
- 注意内存泄漏,分配的内存,记得释放掉;
- MATLAB 中的parfor可以在C++ 中轻松使用OpenMP实现,具体为添加库文件
# include "omp.h"
同时,在for循环前加上如下预编译指令
#pragma omp parallel for
- 使用OpenMP时,配置属性->C++ ->语言->OpenMP支持,选为"是";
1.4 生成解决方案
编写好mex函数后,在项目名称上右键->生成,从而进行编译,生成.mex64文件。
二、调试
- 将生成的.mexw64拷贝到MATLAB当前目录。
- 菜单栏:调试->附加到进程->选择MATLAB进程,附加到进程后,会经历较长时间的符号加载过程;
- 如果符号加载时间过长,可以通过设置符号位置来解决,菜单栏:调试->选项->符号->勾选Microsoft符号服务器;
- 在源代码vlda.cpp中设置断点;
- 在MATLAB中调用.mex64文件,会跳转到VS 2015 中的断点,F10可单步执行;
- 调试过程中修改vlda.cpp,重新生成解决方案,将新生成的mexw64文件拷贝到MATLAB当前目录,此时,需要在matlab中clear掉原来的mexw64文件,即运行命令
clear
三、发布
对于比较简单的程序,直接用Debug版本的也没什么问题,但最好还是使用Release版本。
- 配置属性->配置管理器->活动解决方案配置->Release ,其他设置参照1.2配置项目属性设置。
- 如果mexw64文件需要拷贝到别的电脑上运行,可以考虑采用静态编译。配置属性->C++ ->代码生成->运行库:多线程(/MT);配置属性->常规->MFC的使用:在静态库中使用MFC。
四、总结
将部分核心代码用C++实现后,能够极大的提高运算速度,同时降低内存的使用。另一方面,借助于OpenMP,可以很方便的实现并行计算,将多核CPU的利用率维持在100%。
易夕:MATLAB Tricks 专栏目录zhuanlan.zhihu.com