填充整数列表比填充整数向量快 100 倍

Populating a list of integers is 100 times faster than populating a vector of integers

本文关键字:填充 整数 列表 向量      更新时间:2023-10-16

我正在比较填充整数列表与整数向量所花费的时间。

每个向量和列表填充了1000万个随机整数,并且该实验重复100次以找到平均值。

令我惊讶的是,填充列表比填充整数向量快大约 100 倍。我希望填充整数向量要快得多,因为向量在内存中是连续的,插入要快得多。

填充列表怎么可能比填充向量快 100 倍而不是 10 倍。我确定我错过了一些导致这种情况的概念或想法

这是我用于生成结果的代码

#include <iostream>
#include <sstream>
#include <list>
#include <vector>
#include <ctime>
#include <time.h>
using namespace std;

int main()
{
   list<int> mylist;
   vector<int> myvector;
   srand(time(NULL));
   int num;
   clock_t list_start;
   clock_t list_end;
   clock_t list_totaltime;
   for (int i=0;i<100;i++)
   {
    list_start = clock();
        for (int i = 0 ; i < 10000000 ; i++ ) // 10 million
        {    
            num = rand() % 10000000 ; 
            mylist.push_back(num);
         }
    list_end = clock();
    list_totaltime += difftime(list_end,list_start);
    mylist.clear();
   }
   cout << list_totaltime/CLOCKS_PER_SEC/100;
   cout <<" List is done ";
   cout << endl
        << endl;
   clock_t vector_start;  
   clock_t vector_end;
   clock_t vector_totaltime;
   for (int i=0;i<100;i++)
   {
    vector_start = clock();
        for (int i = 0 ; i < 10000000 ; i++ ) // 10 million times
        {    
            num = rand() % 10000000 ; 
            myvector.push_back(num);
        }
    vector_end = clock();
    vector_totaltime += difftime(vector_end,vector_start);
    myvector.clear();
    }
   cout << vector_totaltime/CLOCKS_PER_SEC/100;
   cout << " Vector is done " ;

}

有人可以向我解释为什么会发生这种情况???

我尝试使用VS2013 C++编译器,std::vectorstd::list得多 (正如我所期望的那样)。

我得到了以下结果:

Testing STL vector vs. list push_back() time
--------------------------------------------
Testing std::vector...done.
std::vector::push_back(): 89.1318 ms
Testing std::list...done.
std::list::push_back(): 781.214 ms

我使用 Windows 高分辨率性能计数器来测量时间。
当然,我在优化的发布版本中进行了测试。

我还重构了推

回循环中的随机数生成,并使用了比rand()更严肃的随机数技术。

您使用clock()来衡量执行时间的方法好吗?

您使用了什么C++编译器?您是否测试了优化的版本?

可编译的测试代码如下:

// Testing push_back performance: std::vector vs. std::list
#include <algorithm>
#include <exception>
#include <iostream>
#include <list>
#include <random>
#include <vector>
#include <Windows.h>
using namespace std;
long long Counter() {
    LARGE_INTEGER li;
    QueryPerformanceCounter(&li);
    return li.QuadPart;
}
long long Frequency() {
    LARGE_INTEGER li;
    QueryPerformanceFrequency(&li);
    return li.QuadPart;
}
void PrintTime(const long long start, const long long finish, 
               const char * const s) {
    cout << s << ": " << (finish - start) * 1000.0 / Frequency() << " ms" << endl;
}
int main() {
    try {
        cout << endl
            << "Testing STL vector vs. list push_back() timen"
            << "--------------------------------------------n"
            << endl;
        const auto shuffled = []() -> vector<int> {
            static const int kCount = 10 * 1000 * 1000;
            vector<int> v;
            v.reserve(kCount);
            for (int i = 1; i <= kCount; ++i) {
                v.push_back((i % 100));
            }
            mt19937 prng(1995);
            shuffle(v.begin(), v.end(), prng);
            return v;
        }();
        long long start = 0;
        long long finish = 0;
        cout << "Testing std::vector...";
        start = Counter();
        vector<int> v;
        for (size_t i = 0; i < shuffled.size(); ++i) {
            v.push_back(shuffled[i]);
        }
        finish = Counter();
        cout << "done.n";
        PrintTime(start, finish, "std::vector::push_back()");
        cout << endl;
        cout << "Testing std::list...";
        start = Counter();
        list<int> l;
        for (size_t i = 0; i < shuffled.size(); ++i) {
            l.push_back(shuffled[i]);
        }
        finish = Counter();
        cout << "done.n";
        PrintTime(start, finish, "std::list::push_back()");
    } catch (const exception& ex) {
        cout << "n*** ERROR: " << ex.what() << endl;
    }
}

有人可以向我解释为什么会发生这种情况???

结果不是真实的,即填充整数列表并不比填充整数向量快 100 倍。您看到的是一个基准工件,由于注释中指出的代码错误。

如果您初始化变量并避免整数除法,那么您应该会看到不同的结果,例如,在我的机器上填充向量比填充列表快 3 倍(顺便说一句,调用vector::reserve()对结果没有影响)。

相关:未初始化变量和编译器(GCC)的乐趣。

此外,不应将difftime(time_t, time_t)clock_t值一起使用。

作为记录,在修复未初始化的变量问题和整数除法后,在x86_64上运行使用 gcc 4.7.3 编译的优化版本和以下标志

g++ -Wall -Wextra -pedantic-errors -pthread -std=c++11 -O3

我得到

0.2 List is done 
0.07 Vector is done

因此,正如我所期望的那样,矢量更快。这不会对代码进行任何进一步的更改。

向量中的元素按顺序存储在连续的内存位置。最初,一些内存被分配给向量,随着您不断向向量添加更多元素,必须进行大量内存操作才能保留向量的这一属性。这些内存操作需要相当长的时间。

而在列表的情况下,head 存储第二个元素的地址,第三个元素的地址存储在第三个元素中,依此类推。这里不需要任何内存重新分配。

但与矢量相比,列表占用更多的存储内存

如果向量的大小超过其容量,则需要重新分配向量。在这种情况下,必须将所有以前的值复制到新存储中。尝试使用vector::reserve增加容量,以减少所需的重新分配。