为啥这段代码运行得这么慢?

Posted

技术标签:

【中文标题】为啥这段代码运行得这么慢?【英文标题】:Why is this code running so slowly?为什么这段代码运行得这么慢? 【发布时间】:2014-01-06 00:38:28 【问题描述】:

我被这段代码严重难住了,我运行了 gprof,发现程序在 contains() 函数中花费了 40% 的时间,该函数运行了大约 8000 次。程序本身总共需要 15 秒才能运行。有谁知道为什么需要这么长时间,或者可能是什么?

// Check a list to see if it contains a tile object at x,y
bool contains(std::list<struct Tile>* list, int x, int y)
  std::list<struct Tile>::iterator it;
  for(it = list->begin(); it != list->end(); it++)
    if((*it).x == x && (*it).y == y)
      return true;
    
  
  return false;

【问题讨论】:

列表搜索效率不高。为什么不使用向量? 嗯,你的名单有多长?线性搜索并不是特别有效(但它与您在链表上获得的效果差不多。) 删除struct,只需Tile。它更干净。 +1 表示“我已经运行了 gprof”。不过请注意答案! 另外,for (Tile t : list) 可能更高效(缓存 list-&gt;end())。 【参考方案1】:

使用std::vector,因为它是缓存友好的,所以它的遍历速度快了大约 100 倍。向量 push_back 具有 O(1) 摊销难度,就像列表一样。无论如何,向量对于中间插入都是不利的。 此外,std::mapstd::unordered_map 专为快速搜索而设计。

【讨论】:

虽然我同意你的一般前提,但 100 倍似乎不太可能。高速缓存行(在 x86 上)为 64 字节。即使T 只有 8 个字节,这也是所需的主内存提取的最大 8 倍...... @OliCharlesworth:和 x86 假设一样,假设缓存中没有任何内容。考虑到 8 字节数据假设,我们谈论的缓存中的值最多是 8 倍,这可以 - 对于某些访问模式和数据大小 - 避免大量主内存提取,以及在任何推测性情况下更好地使用连续内存使用预取.... @TonyD:是的,这很公平。 (虽然对于超过缓存的非常大的数据集,我猜渐近比差异趋向于 8x...) @OliCharlesworth 同意。另外,您可以在预先排序的vector 中进行二分搜索,这对于 dakillakan 的应用程序可能实用,也可能不实用。 @OliCharlesworth:不要忘记 x86 预测内存访问。在最初的几次读取之后,内存控制器将进行预读。此外,现代 RAM 具有更好的线性访问延迟(已空闲一段时间的页面进入睡眠状态)

以上是关于为啥这段代码运行得这么慢?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Tkinter 窗口打开这么慢?

为啥我的代码这么慢?

功能运行太慢...我不明白为啥

android AsyncTask执行为啥这么慢

为啥我的手动调优、支持 SSE 的代码这么慢?

为啥haskell中的递归列表这么慢?