【问题标题】:how to speed up map insertion? [closed]如何加快地图插入? [关闭]
【发布时间】:2018-04-17 05:20:11
【问题描述】:

看起来我终于提高了一点地图插入速度(插入前排序)。您如何看待这些结果?还有优化吗?

#include <map>
#include <iostream>
#include <algorithm>

int main (int argc, char* argv []) {
  //a map<size_t, size_t> random initilisation
  std::map<size_t, size_t> m0, m1;
  {
     std::vector<std::pair<size_t, size_t> > t (10000, std::pair<size_t, size_t> ((size_t) -1, (size_t) -1));
     std::vector<std::pair<size_t, size_t> >::iterator i (t.begin ());
     for (; i != t.end (); ++i) {
       i->first = rand () % 1000000;
       i->second = rand () %1;
     }
     m0.insert (t.begin (), t.end ());
     m1 = m0;
   }
   //vins :
   std::vector<std::pair<size_t, size_t> > vins (10000, std::pair<size_t, size_t> (0, 0));
   {
     std::vector<std::pair<size_t, size_t> >::iterator i (vins.begin ());
     for (; i != vins.end (); ++i) {
       i->first = rand () % 1000000;
       i->second = rand () %1;
     }
   }
   //normal insertion
   clock_t t0 (clock ()), t1 (t0);
   {
     m0.insert (vins.begin (), vins.end ());
   }
   t1 = clock ();
   std::cout << "normal insertion took " << (size_t) (t1 -  t0) << " ticks" << std::endl;
   //sort + hint insertion
   t0 = t1;
   {
     std::sort (vins.begin (), vins.end (), [] (std::pair<size_t, size_t>& p0, std::pair<size_t, size_t>& p1)->bool {
       return (p0.first < p1.first ? true:false);
     });
     std::map<size_t, size_t>::iterator ihint (m1.begin ());
     //std::vector<std::pair<size_t, size_t> >::iterator i (vins.begin ());
     //imroved and more C++11 solution
     std::for_each (vins.begin (), vins.end (), [&ihint, &m1] (std::pair<size_t, size_t>& p) {
       ihint = m1.insert (ihint, p);
     });
   }
   t1 = clock ();
   std::cout << "insertion after sorting took " << (size_t) (t1 - t0) << " ticks" << std::endl;
   if (m0 != m1) std::cout << "but insertion is nok" << std::endl;
   else std::cout << "and insertion is ok" << std::endl;
}

Lenovo Think Center 的结果:

插入耗时 2355 滴答

排序然后插入需要 1706 个滴答声

插入没问题

【问题讨论】:

  • 如果您不需要 ordering 属性,那么std::unordered_map 可能会更快。还要确保打开编译器优化(通常是-O2-O3)。在我的机器上,将这些改进的性能提高了 3 倍以进行正常提示插入,并从第二个结果中剔除几百个刻度。最后,这可能更适合codereview
  • 我正在使用 -Ofast,但我认为 std::map 比 std::unordered_map 更擅长查找。我错了吗?
  • @hnefatl 我删除了我的评论,因为一种类型使我的问题含糊不清。我主要感兴趣的是是否有编译器优化可以使这些映射更快。所以如果我已经在使用std::unordered_map,我可以使用可能的编译器优化让它更快吗?
  • @TitoHamzee 我不认为优化级别会影响地图的速度(标准库已经编译),但它可能能够展开一些循环或强制复制省略或在 this 代码中执行更静态的分析,无论如何这将减少开销。与优化一样,最好只是尝试一下 - 在我的机器上,它确实会提高性能。
  • 如果您添加了包含,这将是一个更容易测试自己的示例。

标签: c++11 stl stdmap


【解决方案1】:

如果您不需要订购商品,那么使用 std::unordered_map 通常比 std::map 更好 - 在大多数实现中,它使用哈希表而不是平衡树,这意味着操作平均O(1) 而不是 O(log n)。此外,它可以从缓存局部性中获得性能提升,因为底层数据结构(数组)通常比树对缓存更友好。

启用-O3(或类似的优化级别)可能会提高您的代码的性能,但不太可能影响地图的插入/查找操作的性能(因为它已经被编译)。请记住,使用-Ofast 意味着编译器不再需要严格遵守标准,这通常不是一个好主意 - 如果性能至关重要并且您已经检查过您的代码是否按预期工作,则使用它,但通常-O3 就够了。


在我的机器(Debian,g++ 6.3.0)上,运行几次并取粗略的平均值:

 Configuration             Normal Hint Insertion   Hint Insertion  
 ------------------------- ----------------------- ---------------- 
  std::map,           -O0                    9750             9200  
  std::map,           -O3                    8000             4250  
  std::unordered_map, -O0                    7000             9700  
  std::unordered_map, -O3                    4200             5000  

【讨论】:

  • 所以无序贴图法线插入(4200)比法线贴图上的提示插入(4250)要好一点。
  • @Saint-Martin 是的,在我的机器上 - 我猜你在提示插入中所做的工作会增加插入的开销,但无助于加速插入本身。您正在对提示插入中的数据进行排序,而 std::unordered_map 没有排序,这可能根本没有帮助。
  • 我的问题是关于有序地图。对不起
  • @Saint-Martin 抱歉,我不确定我是否理解您评论的意思。
猜你喜欢
  • 2013-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-01
  • 1970-01-01
  • 2019-03-26
  • 2013-08-09
  • 1970-01-01
相关资源
最近更新 更多