【问题标题】:Why is this code running so slowly?为什么这段代码运行得这么慢?
【发布时间】:2026-02-05 20:20:03
【问题描述】:

我被这段代码严重难住了,我运行了 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())。

标签: c++ optimization profiling


【解决方案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 具有更好的线性访问延迟(已空闲一段时间的页面进入睡眠状态)