【问题标题】:How to speedup non-sequential array filling?如何加快非顺序数组填充?
【发布时间】:2012-05-13 08:46:41
【问题描述】:

上下文

我有这样的代码:

..
vector<int> values = ..., vector<vector<int>> buckets;
//reserve space for values and each buckets sub-vector
for (int i = 0; i < values.size(); i++) {
  buckets[values[i]].push_back(i);
}
...

所以我得到了一个“桶”,其中包含具有相同值的条目索引。然后在进一步处理中使用这些存储桶。

实际上我正在使用本机动态数组 (int ** buckets;),但为简单起见,我在上面使用了向量。

在装满之前我知道每个桶的大小。

向量的大小约为 2,000,000,000。

问题

如您所见,上面的代码以随机方式访问“buckets”数组。因此,它有不断的缓存未命中,从而大大减慢了执行时间。 是的,我在个人资料报告中看到了这样的失误。

问题

有没有办法提高此类代码的速度?

我尝试创建一个辅助向量并将第一次出现的值放在那里,因此我可以在找到第二个时将两个索引放入相应的存储桶中。这种方法并没有带来任何加速。

谢谢!

【问题讨论】:

  • 使用比int更小的类型。
  • @Pubby 如何以较小的类型存储范围为 0..2,000,000,000 的索引?
  • 你能轻松计算 foo() 的倒数吗? (如果确实是轻量级的,贴一下吧,说不定能给人思路……)
  • 你到底想做什么?对 20 亿个条目进行桶排序,每个可能的最终值一个桶?尝试基数排序以至少减少存储桶的数量...合并排序可能会导致最少的页面错误(并且它是就地的,因此您不需要 14GiB ram)。
  • 如果你想对数组进行排序并且缓存未命中是限制因素,那么显然桶排序不是正确的做法。它似乎是整个例程的主要部分,所以我建议使用并行(就地)合并排序。

标签: c++ arrays performance


【解决方案1】:

您为什么认为是缓存未命中导致您的代码变慢?你有没有介绍过,或者这正是你想到的?

从性能的角度来看,您的代码存在许多非常错误的地方。第一个也是最明显的一点是你从不保留向量大小。发生的情况是您的向量开始时​​非常小(例如,2 个元素),然后每次添加超过大小时,它都会再次调整大小并将内容复制到新的内存位置。如果您说有 2 十亿 个条目,那么您可能会调整大小 30 次!

需要在查看其他改进之前调用函数vector.reserve()(或vector.resize(),具体取决于最适合您的行为)。

编辑

真的吗?你提到你甚至没有在你的 PS 中使用矢量?我们应该如何猜测您的实际代码是什么样的以及它将如何执行?

【讨论】:

  • 正如您在“P.S.”中看到的那样我正在使用本机数组并在 lool 之前分配它们
  • 认真的吗?你提到你甚至没有在你的 PS 中使用矢量?我们应该如何猜测您的实际代码是什么样的以及它将如何执行?您发布的代码与您提出的问题零关系。
  • @bitmask 他说“本机动态数组”,在 C++ 中,它是一个向量,不是吗?
  • @Mahmoud 我猜他的意思是本机(动态分配)数组。
  • @MahmoudAl-Qudsi 你认为对一个你没有读到最后的问题投反对票是一种好习惯吗? ;)
【解决方案2】:

对于给定的时间间隔,foo 是否至少可逆且满射?然后您可以运行该区间并用bar(j,k) 完全填充buckets[j](如果barfoo 的倒数),对于[0,...,MAX_BAR_J) 中的k,然后继续使用j+1 等等。

但是,如果foo 具有散列属性,那么您几乎没有机会,因为您无法预测下一个i 将获得哪个索引。所以我现在看不到机会。

【讨论】:

  • 是的,这个函数就像一个哈希。此外,它可以完全删除,只有值将用作存储桶的索引。很抱歉这样不清楚的陈述。
猜你喜欢
  • 2012-03-03
  • 2011-08-06
  • 1970-01-01
  • 2020-08-23
  • 1970-01-01
  • 2023-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多