为啥这段代码运行得这么慢?
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->end()
)。
【参考方案1】:
使用std::vector
,因为它是缓存友好的,所以它的遍历速度快了大约 100 倍。向量 push_back 具有 O(1) 摊销难度,就像列表一样。无论如何,向量对于中间插入都是不利的。
此外,std::map
和 std::unordered_map
专为快速搜索而设计。
【讨论】:
虽然我同意你的一般前提,但 100 倍似乎不太可能。高速缓存行(在 x86 上)为 64 字节。即使T
只有 8 个字节,这也是所需的主内存提取的最大 8 倍......
@OliCharlesworth:和 x86 假设一样,假设缓存中没有任何内容。考虑到 8 字节数据假设,我们谈论的缓存中的值最多是 8 倍,这可以 - 对于某些访问模式和数据大小 - 避免大量主内存提取,以及在任何推测性情况下更好地使用连续内存使用预取....
@TonyD:是的,这很公平。 (虽然对于超过缓存的非常大的数据集,我猜渐近比差异趋向于 8x...)
@OliCharlesworth 同意。另外,您可以在预先排序的vector
中进行二分搜索,这对于 dakillakan 的应用程序可能实用,也可能不实用。
@OliCharlesworth:不要忘记 x86 预测内存访问。在最初的几次读取之后,内存控制器将进行预读。此外,现代 RAM 具有更好的线性访问延迟(已空闲一段时间的页面进入睡眠状态)以上是关于为啥这段代码运行得这么慢?的主要内容,如果未能解决你的问题,请参考以下文章