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

Posted

技术标签:

【中文标题】填充整数列表比填充整数向量快 100 倍【英文标题】:Populating a list of integers is 100 times faster than populating a vector of integers 【发布时间】:2014-02-17 11:29:32 【问题描述】:

我将填充整数列表与整数向量所花费的时间进行比较。

每个向量和列表都填充了 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 " ;



有人可以向我解释为什么会这样吗???

【问题讨论】:

你需要初始化list_totaltimevector_totaltime。提高编译器警告级别。 当列表大小增加时,不需要重新定位已经定位的内容,这与向量不同(由于连续性)。 它可以防止你的输出完全是垃圾。 你也有整数除法。所以,当我运行你的代码并修复初始化问题时,我得到了0 @juanchopanza 你将 list_totaltime 和 vector_totaltime 初始化为什么??? 【参考方案1】:

我尝试使用 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 高分辨率性能计数器来测量时间。 当然,我在 optimized release build 中进行了测试。

我还重构了推回循环之外的随机数生成,并使用了more serious random number technique than 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() time\n"
            << "--------------------------------------------\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;
    

【讨论】:

我是在 qunicy 2005 编译器上完成的,非常怀疑是否有为此构建的优化工具【参考方案2】:

有人可以向我解释为什么会这样吗???

结果不是真实的,即填充整数列表不是比填充整数向量快 100 倍。由于comments 中的代码pointed out 中的错误,您看到的是基准工件。

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

相关:Fun with uninitialized variables and compiler (GCC).

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

【讨论】:

【参考方案3】:

作为记录,在修复未初始化的变量问题和整数除法之后,在 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

所以,正如我所预料的那样,向量更快。这无需对代码进行任何进一步的更改。

【讨论】:

【参考方案4】:

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

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

但与向量相比,列表需要更多的存储内存

【讨论】:

【参考方案5】:

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

【讨论】:

以上是关于填充整数列表比填充整数向量快 100 倍的主要内容,如果未能解决你的问题,请参考以下文章

在 .NET 中填充整数列表

java aes CBC的填充方式发现

在地图中正确填充列表

为啥快速整数类型比其他整数类型快?

Haskell - 迭代和填充列表

用零填充整数(Java)[重复]