簡體   English   中英

在MATLAB中計算文件中行數的最快方法(Perl比C快嗎?)

[英]Fastest way to count lines in file in MATLAB (Perl faster than C?)

在研究中,我必須計算10+ GB的csv文件中的行數。 在MATLAB上執行此操作的經典方法似乎是使用\\n作為分隔符的textscan() ,但這會占用大量內存,而且速度非常慢。 建議我編寫一個Perl腳本,並使用str2double(perl('countlines.pl', path))調用它,這似乎要快得多:

# countlines.pl
while (<>) {};
print $.,"\n";

然后,我想看看我是否可以編寫一個在C中執行相同功能但沒有運氣的MEX函數,是否具有任何優勢,更令人驚訝的是,我發現它比Perl腳本慢了大約10倍(使用LLVM編譯器Xcode 4.6.3):

//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);
}

所以,

  1. 除了網關功能之外,MEX功能中的這些開銷又來自何處?
  2. 我還能做些什么來加快速度? 只要我們可以獲取與MATLAB交互的例程,我就可以使用任何語言。 似乎唯一的其他方法是對文件的內存進行映射,並將工作負載分配到幾個內核中。

除了網關功能之外,MEX功能中的這些開銷又來自何處?

  1. MEX函數正在分配內存。
  2. 該函數將內存轉換為字符串。
  3. 該函數正在創建一個雙精度矩陣。

無法與Perl的簡單行計數功能進行比較,因為它們在功能上並不等效。

我還能做些什么來加快速度? 是的,只數行。
沒有多余的東西,例如以雙精度矩陣讀取。

這是使用C ++對文本文件中的行進行計數的示例:

std::ifstream text_file(/*...*/);
std::string   text_from_file;
unsigned int  line_count = 0;
while (std::getline(text_file, '\n'))
{
  ++line_count;
}

比較性能時,功能必須等效。

編輯1:
決定。 你在數線嗎?

您是否要計算矩陣中的行數?

你想算在一個文件中的行?

如果要計算矩陣中的行數,則需要修改Perl腳本。

如果希望MEX函數僅對行進行計數,請刪除對計數線功能的調用countlines所有內容。

為什么要使用double行數?
您是否期望小數行計數?

您要使用CI / O還是C ++ I / O?

逐塊讀取數據將加快CI / O功能:

#define MAX_CHUNK_SIZE 1024*1024
char buffer[MAX_CHUNK_SIZE];
size_t chars_read = 0;
unsigned int line_count = 0;
//...
while (!feof(inputFile))
{
  chars_read = fread(buffer, 1, MAX_CHUNK_SIZE, input_file);
  char c;
  for (unsigned int i = 0; i < chars_read; ++i)
  {
     if (c == '\n')
     {
       ++line_count;
     }
  }
}

訪問文件的瓶頸是查找數據的開銷。 大量讀取可減少開銷。

您是否已閱讀有關此主題的Perl常見問題解答,其中提供了大約6個示例?

perldoc -q'如何計算文件中的行數'

wc命令已被移植到Windows,因此如果要安裝它可能是最好的解決方案。 否則,我將在wc示例之前使用Perl示例(下面已修復和優化)。

    my $lines = 0;
    open my $fh, '<:raw', $filename
        or die "Can't open $filename: $!";
    while( sysread $fh, $buffer, 64*1024 ) {
        $lines += ( $buffer =~ tr|\n||; );
    }
    close $fh;

在這段代碼中要計算總行數。 但是,這需要幾個迷你。

my $lines = do {
    open my $fh, '<', "filename" or die "Can't open filename: $!";
    1 while (<$fh>);
    $.
};
print "Total number of lines: $lines\n";

為了有效地計算行數,只需執行以下操作:

int main()
{
   unsigned long lines = 0;
   int c; /* c must be an int, not char */

   while ((c = getchar()) != EOF) 
      if (c == '\n') 
         lines++;
   printf("%lu\n", lines);
   return 0;
} /* main */

我認為在Kernighan&Ritchie中有一個類似的例子,即使不是相同的話。 而且請下次不要使用double精度數。 使用整數類型進行計數要比使用浮點數進行計數更為有效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM