【发布时间】:2020-11-05 05:16:08
【问题描述】:
我正在编写一个 C++ 程序来在一个巨大的图形上执行计算,因此必须尽可能快。我有一个 100MB 的未加权边文本文件,并将它们读入整数的二维向量(第一个索引 = nodeID,然后是具有该节点边缘的节点的 nodeID 的排序列表)。此外,在程序中,边将按照它们在列表中的存储顺序进行查找。所以我的期望是,除了一些更大的差距之外,它总是可以很好地预加载到缓存中。然而,根据我的分析器,遍历玩家的边缘是一个问题。因此我怀疑,二维向量没有紧凑地放在内存中。
如何确保我的 2D 向量尽可能紧凑,并且子向量按应有的顺序排列? (例如,我想从二维向量创建一个“二维数组”,首先是指针数组,然后是列表。)
顺便说一句:如果不清楚:节点可以有不同数量的边,因此没有选择正常的二维数组。有一些边缘很多,但大多数边缘很少。
编辑:
我已经解决了这个问题,我的程序现在的速度是原来的两倍多: 有第一个解决方案,然后略有改进:
-
我将邻居 id 列表放入一维整数数组中,并有另一个数组知道某个 id 的邻居列表从哪里开始
-
通过将指针数组(指针需要 64 位)替换为包含索引的 32 位整数数组,我得到了明显的加速
【问题讨论】:
-
要使二维向量或数组紧凑,请将其声明为 (width * height) 元素的一维数组。您始终可以根据行和列坐标计算一维数组的索引。更多的压缩需要压缩算法。
-
优化的另一个想法是使用结构或类的数组而不是二维数组。结构确保项目在缓存中彼此相邻;否则处理器可能不得不重新加载缓存以获取另一列中的值。
-
您可能会发现 Mike Acton 关于data-oriented design 的讨论很有用,尤其是在 36 分钟左右。它不能直接解决您的问题,但它可能会为您提供一些关于如何确保您的数据是缓存友好的想法。这次谈话无疑改变了我对在代码中传递和使用数据的看法。
-
@ThomasMatthews 我为我的国际象棋引擎使用了伪二维数组技巧,但不幸的是我无法计算索引,因为我必须知道之前有多少条目。还是您的意思是将子列表彼此相邻存储在一个数组中,并让另一个数组指向一个玩家开始的位置?我猜那太棒了!
-
@ThomasMatthews 我不明白结构的想法。所以一个结构数组和每个结构内的子列表??
标签: c++ arrays caching vector memory-management