【发布时间】:2014-08-09 17:19:09
【问题描述】:
在我的研究中,我必须计算 10+ GB csv 文件中的行数。在 MATLAB 上执行此操作的经典方法似乎是使用 textscan() 和 \n 作为分隔符,但这会占用大量内存并且速度非常慢。有人建议我编写一个 Perl 脚本并使用 str2double(perl('countlines.pl', path)) 调用它,这似乎确实要快得多:
# countlines.pl
while (<>) {};
print $.,"\n";
然后,我想看看在 C 中编写一个 MEX 函数是否有任何优势,但没有运气,更令人惊讶的是,我发现这比 Perl 脚本慢了大约 10 倍(使用Xcode 4.6.3 上的 LLVM 编译器):
//countlines.c
#include "mex.h"
void countlines(char *filepath, double *numLines)
{
/* Routine */
numLines[0] = 0;
FILE *inputFile = fopen(filepath, "r");
int ch;
while (EOF != (ch=getc(inputFile)))
if ('\n' == ch)
++numLines[0];
}
void mexFunction( int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
/* Gateway function */
int bufferLength, status;
char *filepath; // Input: File path
double *numLines; // Output Number of lines
bufferLength = (mxGetM(prhs[0]) * mxGetN(prhs[0])) + 1; // Get length of string
filepath = mxCalloc(bufferLength, sizeof(char)); // Allocate memory for input
// Copy the string data from prhs[0] into a C string
status = mxGetString(prhs[0], filepath, bufferLength);
if (status != 0)
mexErrMsgIdAndTxt("utils:countlines:insufficientSpace", "Insufficient space, string is truncated.");
// Create the output matrix and get a pointer to the real data in the output matrix
plhs[0] = mxCreateDoubleMatrix(1,(mwSize)1,mxREAL);
numLines = mxGetPr(plhs[0]);
// Call the C routine
countlines(filepath, numLines);
}
所以,
- 除了网关功能之外,MEX 功能中的这些开销来自哪里?
- 我还能做些什么来加快速度吗?只要我们可以让例程与 MATLAB 交互,我愿意使用任何语言。似乎唯一的其他方法是内存映射文件块并将工作负载拆分到几个内核。
【问题讨论】:
-
在linux上可以使用系统命令
wc -l < filename。 -
按照 PetrH 的建议,您是否尝试在 MATLAB 中使用
system调用它? -
是的!非常感谢。我尝试了
[~,output] = unix(strcat('wc -l < ', path)); numLines = str2double(output);,它比 Perl 方法稍快。我将它封装在if isunix块中,并将Perl 方法保留在else块下。 :) -
wc -l绝对是如果 Matlab 在本机上执行速度很慢的方法,但如果文件名包含空格或任何其他 shell 元字符,strcat('wc -l < ', path)将失败。您需要先将路径转换为文字。您需要的代码是die if $path =~ /\0/; $path =~ s/'/'\\''/g; $path = "'".$path."'";的 Matlab 等效代码
标签: c++ c performance perl matlab