【发布时间】:2019-07-26 03:30:21
【问题描述】:
这是一个愚蠢的问题,但它一直困扰着我,我无法通过谷歌解决它。
考虑以下数组:
struct SomeDataStruct
{
uint64_t ValueOne;
uint64_t ValueTwo;
uint64_t ValueThree;
};
SomeDataStruct _veryLargeArray[1024];
现在,哪些方法可以更快地遍历每个元素并对每个元素进行处理?
方法一:
for (int i = 0; i < 1024; ++i)
{
_veryLargeArray[i].ValueOne += 1;
_veryLargeArray[i].ValueTwo += 1;
_veryLargeArray[i].ValueThree = _veryLargeArray[i].ValueOne + _veryLargeArray[i].ValueTwo;
}
方法二:
SomeDataStruct * pEndOfStruct = &(_veryLargeArray[1024]);
for (SomeDataStruct * ptr = _veryLargeArray; ptr != pEndOfStruct; ptr += 1)
{
ptr->ValueOne += 1;
ptr->ValueTwo += 1;
ptr->ValueThree = ptr->ValueOne + ptr->ValueTwo;
}
我知道这个问题表面上看起来真的很愚蠢,但我想知道的是编译器是否对每种给定的实现 for 循环的方式做了一些聪明/特殊的事情?在第一种情况下,如果编译器实际上每次都查找 BaseArrayPointer + Offset 可能会占用大量内存,但如果编译器足够聪明,如果会用整个数组填充 L2 缓存并处理 {} 之间的代码正确。
如果编译器每次都解析指针,则第二种方法可以解决,但可能会使编译器很难确定是否可以将整个数组复制到 L2 缓存中并在那里遍历。
很抱歉提出这么愚蠢的问题,我在学习 c++ 时获得了很多乐趣,并且已经开始做你想太多的事情。只是好奇是否有人知道是否有“明确”的答案。
【问题讨论】:
-
你问的是什么平台?在主要的桌面平台上,“将数组复制到 L2”不是编译器的工作,而是有 MMU 硬件。
-
在某些情况下,编译器甚至可能为两个循环生成相同的代码。您不应该注意到任何性能差异。此外,为了可读性,我建议您对这些选项中的任何一个使用范围 for 循环。
-
每个编译器都有自己的一组优化。在架构上为编译器获得明确答案的唯一方法是分析代码。 (好吧,如果循环恰好编译成相同的机器代码,我猜你不必实际运行它就知道它们具有相同的性能。)
-
在这种情况下使用结构或数组将更容易对代码进行矢量化
标签: c++ arrays for-loop optimization