Matlab向C++ Eigen传递大矩阵:Map类两种实现耗时差异疑问
问题描述
我尝试将大型复矩阵从Matlab传递至采用Eigen库的C++ Mex API函数,基于Eigen的Map类设计了两种实现方案,将输入的TypedArray复双精度矩阵映射为Eigen复双精度矩阵。我原本认为Map类不会产生拷贝操作,因此无论矩阵大小,执行耗时都应极低。
两种实现代码如下:
实现1
matlab::data::TypedArray<std::complex<double>> inIDXT = std::move(inputs[1]); Eigen::MatrixXcd idxt = Eigen::Map< Eigen::MatrixXcd > (inIDXT.release().get(), numEl*na, nPoints);
实现2
matlab::data::TypedArray<std::complex<double>> inIDXT = std::move(inputs[1]); auto idxtData = inIDXT.release(); Eigen::Map< Eigen::MatrixXcd > idxt(idxtData.get(), numEl*na, nPoints);
使用std::chrono::steady_clock::now()计时,通过Matlab的mex命令,采用MinGW64编译器(等效于gcc 6.3)编译运行。测试发现,针对14400×73728的复双精度输入矩阵,实现2耗时约30-40秒,实现1耗时约150秒。疑惑点在于:为何该映射操作会产生耗时,以及两种实现存在显著耗时差异的原因。
解答
1. 映射操作耗时的真实来源
你观测到的耗时并非来自Eigen的Map映射本身,而是来自两个隐藏环节:
- Matlab的
TypedArray::release()会触发内存所有权转移,这个过程中Matlab需要执行内部内存管理操作(如解锁内存区域、更新引用计数),对于超大型矩阵,这类操作的开销无法忽略。 - 计时范围可能包含了Matlab向Mex函数传递数据的前期准备,或是后续的内存清理流程,并非完全是Map相关操作的耗时。
2. 两种实现的耗时差异核心原因
两者的本质区别是是否触发了Eigen矩阵的全量数据拷贝:
- 实现2中,
idxt是Eigen::Map<MatrixXcd>类型,它只是原内存的一个视图,没有任何数据拷贝,唯一的开销是release()带来的内存管理操作。 - 实现1中,你将
Eigen::Map赋值给了Eigen::MatrixXcd对象——这会触发MatrixXcd的拷贝构造函数,把Map指向的所有数据完整拷贝到新分配的内存中。对于14400×73728的复矩阵,总元素数超过10亿,每个元素占16字节(双精度复数),总数据量超过16GB,如此大规模的拷贝操作必然消耗大量时间,这就是实现1耗时是实现2数倍的根本原因。
简单来说,实现1的代码等价于:
Eigen::Map<Eigen::MatrixXcd> temp_map(inIDXT.release().get(), numEl*na, nPoints); Eigen::MatrixXcd idxt = temp_map; // 此处发生全量数据拷贝
3. 优化建议
如果不需要修改原数据,或不需要Eigen矩阵的可独立修改/移动特性,直接使用Eigen::Map类型即可,完全避免拷贝开销。如果确实需要拥有独立的矩阵副本,再考虑赋值给MatrixXcd,但需提前做好耗时准备。
内容的提问来源于stack exchange,提问作者drakon101
相关产品推荐
相关产品推荐

