这是一个简化的例子。请注意,我选择了简单类型,但在应用程序中我可能有更多属性
struct object
{
float a, b;
int c;
};
vector<object> objects;
或
vector<float> a, b;
vector<int> c;
在至少访问一次属性的游戏应用程序中,性能可能会有所不同。无论如何,游戏循环都将贯穿整个索引。
我知道第一个示例更方便(使用单个结构组织代码要容易得多)并且可能取决于应用程序实际执行的操作,但第二个示例是否更加缓存友好?
我知道这不是最初使用Knuth过早优化的东西制作应用程序的正确方法,但我只是想知道......我已经在gamedev幻灯片中读过一次,我想知道是否这是真的与否,以及为什么。
答案 0 :(得分:2)
“这取决于!”
实际上,对于所有问题,不仅有一个最佳数据分布,否则编译器和编程语言将围绕它构建。
这取决于大部分时间花在计算上的算法。
因此,array-of-structs对缓存更友好/页面错误更友好; struct-of-arrays更适合SSE / AVX SIMD优化,具有更好的内存通道利用率(例如CUDA就是如此)。
我首选的方法是开始使用对象数组,并仅使用接口(getter / setters)。比试图优化使对象成为底层数组的接口,如果我有证据表明我缺少一些重要的优化通过分析。
并且记住......“早期优化是所有编程的邪恶”;)
答案 1 :(得分:1)
在我看来,最好只有一个类对象向量而不是其数据成员的三个向量。在最后一种情况下,所有操作都重复三次,包括内存分配/释放。
在最后一种情况下,Mpreover存在逻辑不一致,因为这三个向量不与对象连接。您将无法找到包含这些属性的对象。
答案 2 :(得分:1)
由于数据位置和缓存友好性,一个对象向量可能会表现得更好,但最好通过实际分析您的使用场景来确定,这尤其取决于您的访问模式。
答案 3 :(得分:1)
如果a,b,c是相关的并且可能会一起读取,则结构更加缓存友好。
但是将所有相同数据类型顺序放在内存中的打包具有可能(自动)可矢量化的优点。
无论如何,一些相关问题需要深入研究这个问题: