我有1MB的文本文件。 我想删除空格,新行,制表符,并将字符大小写从1KB文件的小写转换为大写,然后迭代4KB。
我已经写了这段代码:
for (i = 0, j= 0; i < size; ++i)
{
switch (Buffer[i])
{
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
NormalisedBuffer[j] = Buffer[i] - 32;
++j;
break;
case ' ':
case '\t':
case '\r':
case '\n':
break;
default:
NormalisedBuffer[j] = Buffer[i];
++j;
}
}
有没有办法以更少的时间和效率的方式做到这一点?
答案 0 :(得分:1)
虽然OP声称处理100个文件需要12秒,但测量速度要快得多。
TL; DR;
Time for OPs method: 0.006472 seconds
Faster method: 0.005364 seconds
首先,让我们定义测量指标:我们忽略了在文件I / O上花费的时间,因为在我们关注的实现级别中无法避免这种情况。
我们使用这个界面定义数据处理功能:
int testcase (uint8_t* des, size_t deslen, const uint8_t* src, size_t srclen);
然后,我们测量N次迭代所花费的时间,为简单起见,我们选择N = 1:
T0 = chrono::system_clock::now();
test_base(des1, testdata_size, src, testdata_size);
T1 = chrono::system_clock::now();
一旦我们有了更科学的测量,我们现在就什么更快就有了客观的想法。 但是,我应该指出,在所有情况下都没有最快的通用算法,这就是为什么你有不同的算法。
对于此特定测试,我们应该考虑输入样本空间并设计一个处理,以便在统计上针对此类输入样本进行优化。
我假设输入样本是计划英语,大多数是ASCII字符,而在较小的情况下,几乎没有TAB,SPACE和换行;如果不是这样,我的方法会慢一些。
现在,根据上述假设,我会跟踪已处理的字符,并将输出与memcpy
组合在一起,这会在这种特定情况下产生稍快的度量。
完整来源:使用clang -lstdc++ -O2 a.cpp -o a
#include <chrono>
#include <iostream>
#include <unistd.h>
#include <math.h>
using namespace std;
int test_base(uint8_t* des, size_t deslen, const uint8_t* src, size_t srclen) {
int i, j;
if ( deslen < srclen ) return -1;
for (i=0, j=0; i<srclen; ++i) {
switch (src[i]) {
case 'a':
case 'b':
case 'c':
case 'd':
case 'e':
case 'f':
case 'g':
case 'h':
case 'i':
case 'j':
case 'k':
case 'l':
case 'm':
case 'n':
case 'o':
case 'p':
case 'q':
case 'r':
case 's':
case 't':
case 'u':
case 'v':
case 'w':
case 'x':
case 'y':
case 'z':
des[j] = src[i] - 32;
++j;
break;
case ' ':
case '\t':
case '\r':
case '\n':
break;
default:
des[j] = src[i];
++j;
}
}
return 0;
}
int testcase_1(uint8_t* des, size_t deslen, const uint8_t* src, size_t srclen) {
const uint8_t* end = src + srclen;
const uint8_t* head = src;
size_t len;
if ( deslen < srclen ) return -1;
for (; src < end; src++) {
uint8_t value = *src;
if ( value >= 'a' && value <='z' ) {
size_t len = (size_t)(src - head);
if ( len > 0 ) memcpy ( des, head, len );
des[len] = value-32;
des += len+1;
head = src+1;
} else if ( value == ' ' || value == '\t' || value == '\r' || value == '\n' ) {
size_t len = (size_t)(src - head);
if ( len > 0 ) memcpy ( des, head, len );
des += len;
head = src+1;
} else {
// Do Nothing
}
}
return 0;
}
int main(int argc, char* argv[]) {
chrono::time_point<chrono::system_clock>T0, T1;
uint64_t duration;
// Create test data
uint8_t *src, *des1, *des2;
const size_t testdata_size = 1024*1024; // 1MB
src = new uint8_t[testdata_size];
des1 = new uint8_t[testdata_size];
des2 = new uint8_t[testdata_size];
// TODO: seed
for ( size_t i=0; i<testdata_size; i++ ) {
src[i] = (uint8_t)rand();
}
// Put things in cache and realize the memory
memset ( des1, 0, testdata_size);
memset ( des2, 0, testdata_size);
T0 = chrono::system_clock::now();
test_base(des1, testdata_size, src, testdata_size);
T1 = chrono::system_clock::now();
duration = chrono::duration_cast<std::chrono::nanoseconds>(T1-T0).count();
cout << "Duration: " << (duration/1.0E9) << endl;
T0 = chrono::system_clock::now();
testcase_1(des2, testdata_size, src, testdata_size);
T1 = chrono::system_clock::now();
duration = chrono::duration_cast<std::chrono::nanoseconds>(T1-T0).count();
cout << "Duration: " << (duration/1.0E9) << endl;
if ( memcmp ( des1, des2, testdata_size ) == 0 ) {
cout << "Meaningless compare to prevent optimize!";
}
delete des2;
delete des1;
delete src;
return 0;
}