超慢C ++ For循环

时间:2019-10-21 22:15:04

标签: c++

在解析二进制数据时,遇到了我没想到的事情,但是与C#中的类似方法相比,for循环确实很慢。在此之前,我已经从文件中读取到std::vector<unsigned char> BufferedLine中,而所有要做的就是将300个字符的缓冲区分解为80个不同宽度的列。

    char* locale = setlocale(LC_ALL, "UTF-8");
    std::vector<unsigned char> CurrentColumnBytes(ColumnBytes.ColumnWidth);
    int arraySize = CurrentColumnBytes.size();
    int start=ColumnBytes.StartingPosition;
    int width=ColumnBytes.ColumnWidth + ColumnBytes.StartingPosition;
    stopwatch<> sw;
    for (int C = start; C < width; ++C)
    {
        int Index = C - ColumnBytes.StartingPosition;
        CurrentColumnBytes[Index] = BufferedLine[C];
    }
    std::cout << "Elapsed: " << duration_cast<double>(sw.elapsed()) << '\n';

这包裹在另一个for循环中,该循环对每列数据执行相同的操作。对于每个单元格,其输出:

Elapsed: 0.0029621
Elapsed: 0.0012005
Elapsed: 0.0012492
Elapsed: 0.0010724
Elapsed: 0.0010622
Elapsed: 0.0009512
Elapsed: 0.0012072

这似乎并不长,但这是基于数据库的CELL的,这意味着它每秒仅解析约25行。当我对整行进行测量时,平均约为0.07

这是Byte结构的相关部分:

struct Byte
{
    std::string  DataType;
    int  ColumnWidth;
    int StartingPosition;
    std::string Column;
    std::vector<unsigned char> data;

    int size() { 
        return this->data.size();
    }
};

通常在秒表的打印位置下方会进行其他处理,但是出于调试和性能测试的目的,我将其全部注释掉。它是在VS2019中编译的,并在具有24个2.4GHz内核和64GB RAM的PC上启用了优化,并带有以下开关:

/JMC /permissive- /MP /GS /analyze- /W3 /Zc:wchar_t /I"C:\BitBucket\boost_1_71_0\stage\lib" /I"C:\BitBucket\boost_1_71_0\" /ZI /Gm- /O1 /sdl /Fd"Debug\vc142.pdb" /Zc:inline /fp:precise /D "_CRT_SECURE_NO_WARNINGS" /D "_MBCS" /errorReport:prompt /WX- /Zc:forScope /Gd /Oy- /MDd /std:c++17 /FC /Fa"Debug\" /EHsc /nologo /Fo"Debug\" /Fp"Debug\Project1.pch" /diagnostics:column 

更改优化类型会给我以下时间。这些是每整行,而不是上面的每个单元格。

//O1
Elapsed: 0.0760841
Elapsed: 0.0479458
Elapsed: 0.102819
Elapsed: 0.0902831
Elapsed: 0.0458162
Elapsed: 0.045791
Elapsed: 0.0464516
Elapsed: 0.0466347
Elapsed: 0.0457104

//O2    
Elapsed: 0.0913771
Elapsed: 0.0419886
Elapsed: 0.042406
Elapsed: 0.0435289
Elapsed: 0.0402844
Elapsed: 0.0447555
Elapsed: 0.0411286

//Ox
Elapsed: 0.0655737
Elapsed: 0.0413363
Elapsed: 0.04166
Elapsed: 0.0405113
Elapsed: 0.0398387
Elapsed: 0.0399873
Elapsed: 0.0386572
Elapsed: 0.0376599
Elapsed: 0.0427373
Elapsed: 0.0380113
Elapsed: 0.0400754

当我在C#中执行这些相同的步骤时,我获得了近20万个单元/秒。我的C ++是否有突出的问题?我之前曾问过有关数据类型和性能的问题,不确定不确定的char型向量是否与此有关,但这似乎需要很长时间才能将几个字节从一个数组复制到另一个数组。

秒表定义:

template <typename Clock = std::chrono::steady_clock>
class stopwatch
{
    typename Clock::time_point last_;

public:
    stopwatch()
        : last_(Clock::now())
    {}

    void reset()
    {
        *this = stopwatch();
    }

    typename Clock::duration elapsed() const
    {
        return Clock::now() - last_;
    }

    typename Clock::duration tick()
    {
        auto now = Clock::now();
        auto elapsed = now - last_;
        last_ = now;
        return elapsed;
    }
};

template <typename T, typename Rep, typename Period>
T duration_cast(const std::chrono::duration<Rep, Period>& duration)
{
    return duration.count() * static_cast<T>(Period::num) / static_cast<T>(Period::den);
}

更新

我在Wandbox上找到了一个可行的示例:https://wandbox.org/permlink/VIvardJNAMKzSbMf

由于某种原因,它运行以下时间:

Elapsed: 0.00115457
Elapsed: 0.000815412
Elapsed: 0.000814636

但是我PC上的代码完全相同:

Elapsed: 0.05275
Elapsed: 0.02782
Elapsed: 0.0283161

1 个答案:

答案 0 :(得分:0)

我做了更多的工作,然后将其用于另一个问题:C++ Perfomance Per Compiler, 200 times slower than C#

部分原因是重做循环,部分原因是正在使用的编译器。我能够以大约50,000行/秒,每行80列的速度使C ++处理文件。我重新设计了整个工作流程,以确保完全不必回溯。我首先将整个文件读入ByteArray,然后通过将数据从一个数组移动到另一个数组而不是在for循环中指定每个字节来逐行遍历。然后,我使用地图来存储数据。

stopwatch<> sw;
    while (CurrentLine < TotalLines)
    {
        int BufferOffset = CurrentLine * LineLength;
        std::move(ByteArray + BufferOffset, ByteArray + BufferOffset + LineLength, LineByteArray);
        for (int i = 0; TotalColumns > i + 1; ++i)
        {
            int ThisStartingPosition = StartingPosition[i];
            int ThisWidth = ColumnWidths[i];
            std::uint8_t* CurrentColumnBytes;
            CurrentColumnBytes = new uint8_t[ThisWidth];
            {
                std::move(LineByteArray + ThisStartingPosition, LineByteArray + ThisStartingPosition + ThisWidth, CurrentColumnBytes);
                ResultMap[CurrentLine][i] = Format(CurrentColumnBytes, ThisWidth, DataType[i]);
            }
        }
        CurrentLine++;
    }
    std::cout << "Processed" << CurrentLine << " lines in : " << duration_cast<double>(sw.elapsed()) << '\n';