如何加快加载文本文件到多向量

How to speed up loading text file to multi vector

本文关键字:向量 文件 文本 何加快 加载      更新时间:2023-10-16

我必须加载带有数据的大文件(几个GB(,我想将它们加载到二维向量。下面的代码可以完成这项工作,但它非常慢。更具体地说,目标是获取所有行,而第二列中的值等于索引(_lh,_sh(。然后排除第四列值与线 1和线路1相同的行。现在,我是C 的新手,我在Python中使用了常规代码(已经有此问题的工作代码(。但是我需要它的速度尽可能快,因此我试图将我的Python代码重写为C 。但是它比现在比Python慢(仅将数据传达给向量(...因此,在我继续之前,我想改进这一点。根据我在类似问题中发现的问题,问题将是动态向量,.push_back((和getline((。

我对类似问题中提到的映射和块加载感到困惑,因此我无法更改这些代码。

您能帮我优化此代码吗?

谢谢。

#include <iostream>
#include <sstream>
#include <fstream>
#include <array>
#include <string>
#include <vector>
using namespace std;
int pixel(int radek, int sloupec, int rozmer = 256) {
    int index = (radek - 1) * rozmer + sloupec;
    int index_lh = (index - rozmer - 1);
    int index_sh = (index - rozmer);
    int index_ph = (index - rozmer + 1);
    int index_l = (index - 1);
    int index_p = (index + 1);
    int index_ld = (index + rozmer - 1);
    int index_sd = (index + rozmer);
    int index_pd = (index + rozmer + 1);
    array<int, 9> index_all = { {index, index_lh, index_sh, index_ph, index_l, index_p, index_ld, index_sd, index_pd } };
    vector<vector<string>> Data;
    vector<string> Line;
    string line;
    for (int m = 2; m < 3; m++) {
        string url = ("e:/TPX3 - kalibrace - 170420/ToT_ToA_calib_Zn_" + to_string(m) + string(".t3pa"));
        cout << url << endl;
        ifstream infile(url);
        if (!infile)
        {
            cout << "Error opening output file" << endl;
            system("pause");
            return -1;
        }
        while (getline(infile, line))
        {
            Line.push_back(line);
            istringstream txtStream(line);
            string txtElement;
            vector<string> Element;
            while (getline(txtStream, txtElement, 't')){
                Element.push_back(txtElement);
            }
            Data.push_back(Element);
        }
    }
    cout << Data[1][0] << ' ' << Data[1][1] << ' ' << Data[1][2] << endl;
    return 0; 
}
int main()
{   
    int x = pixel(120, 120);
    cout << x << endl;
    system("pause");
    return 0;
}

向量经常重新分配其基础缓冲区,可能会变得慢。需要在连续内存的缓冲区上实现向量,并且每次超过缓冲区限制时,它都必须分配一个新的和较大的缓冲区,然后将内容从旧缓冲区复制到新的缓冲区。如果您知道需要多大的缓冲区(不需要擦干(,则可以帮助程序分配适当尺寸的缓冲区,例如使用例如。Data.reserve(n)(其中n大约是您认为需要的元素数(。这确实注意到了矢量的"大小",只是基础缓冲区的大小。总之,我不得不说我从未真正对此进行基准测试,因此这可能会或可能不会改善您的程序的性能。

编辑:不过,我认为性能更有可能由Data.push_back(Element);行瓶装,该行可以复制元素矢量。如果您使用的是C 11,我相信可以通过执行Data.emplace_back(std::move(Element));之类的操作来解决此问题,在这种情况下,您将无法更改Element(内容已移动(。您还需要为std::move包含memory

在段循环中,您可以尝试从

更改行
while (getline(infile, line))
{
    Line.push_back(line);
    istringstream txtStream(line);
    string txtElement;
    vector<string> Element;
    while (getline(txtStream, txtElement, 't')){
        Element.push_back(txtElement);
    }
    Data.push_back(Element);
}

to:

while (getline(infile, line))
{
    Line.push_back(line);
    istringstream txtStream(line);
    string txtElement;
    //vector<string> Element; [-]
    Data.emplace_back(); // [+]
    while (getline(txtStream, txtElement, 't')) {
        //Element.push_back(txtElement); [-]
        Data.back().push_back(txtElement); // [+]
    }
    //Data.push_back(Element); [-]
}

这样,Data中的向量不需要在此处移动或复制 - 它们已经构造,尽管是空的。Data中的向量使用.emplace_back()默认构造。我们使用.back()功能获得Data中的最后一个元素,并像往常一样使用.push_back()来推动我们的值。希望这会有所帮助:(

您可以尝试使用旧的C文件读取API(FILE*fopen()等(或为std::istringstream设置更大的缓冲区,如下所示

constexp std::size_t  dimBuff { 10240 } // 10K, by example
char myBuff[dimBuff];
// ...
istringstream txtStream(line);
txtStream.rdbuf()->pubsetbuf(myBuff, dimBuff);

您可以尝试的另一件事是使用std::deque S代替std::vector S(但是我不知道这是否有用(。

MUOS建议,您可以使用移动语义;您也可以使用emplace_back()

所以我建议尝试

Element.push_back(std::move(txtElement));
Data.push_back(std::move(Element));

Element.emplace_back(std::move(txtElement));
Data.emplace_back(std::move(Element));

您也可以使用以下行(如果我没错的话,从std::istringstream的字符串中没有移动构造函数(

Line.push_back(line);
istringstream txtStream(line);

添加移动语义(和emplace_back()(

istringstream txtStream(line);
Line.emplace_back(std::move(line));

P.S。:显然reserve()是有用的

您还可以在向量上使用reserve(int),以便它们更接近目标大小。

也可以避免在堆周围跳很多矢量,因为仅重新创建矢量会通过目标大小。

如果向量通过您先前保留的大小,则可以再次致电储备金:

vector<int> vec;
vec.reserve(10);
for (int i=0;i < 1000; i++)
{
    if ( vec.size() == vec.capacity() )
    {
        vec.reserve(vec.size()+10);
    }
    vec.push_back(i);
}