最有效的方法来规范化1MB文本文件?

时间:2014-08-23 08:22:58

标签: c++ c

我有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;
        }
    }

有没有办法以更少的时间和效率的方式做到这一点?

1 个答案:

答案 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;
}