std::array 在存储大对象时是否仍然缓存友好?
Is std::array still cache friendly when it stores large objects?
我知道 std::array 是缓存友好的,因为存储在 std::array 中的所有项目都紧密地排列在一起。如果我遍历数组,当我尝试访问一个项目时,CPU 会 预取 接下来的几个项目。
这就是我的困惑所在:通常 XEON 缓存行是 64 字节:即 8 int64_t 。成像我有
std::array<BigObject, 100>
其中每个 BigObject 的大小为 512 字节。在那种情况下,即使所有 BigObject 项目都彼此相邻打包,CPU 也无法做任何聪明的事情:它仍然必须逐行获取缓存,即每个 BigObject 8 行。因此,应该没有任何缓存友好的优势。
那么我的问题是:对于std::array大对象,是否还有缓存友好的优势?如果是这样,为什么?
澄清一下,处理器高速缓存的加速源于这样一个事实,即当今计算机的 RAM(即内存)比 CPU 慢几倍。所以 CPU 有一些小的内部存储器,所谓的缓存,速度很快。为了最好地利用小内存,CPU通常使用时间和space的概念,意思是经常使用的东西保存在缓存中,最近使用的东西旁边的东西,它们的邻居在内存,也被加载到缓存中,因为接下来很可能需要它们。
正如您所理解的那样,当事物在内存中紧密相连时,它们会被友好地缓存。由于 std::array
和 std::vector
被称为 ContiguousContainer,它们在内存中将它们的内容相邻保存。
因此,缓存友好确实可以将您经常一起使用的东西保存在一起,即您在循环中迭代或在这样的容器中一个接一个地使用。
如果你的对象像你说的那么大,你可以做你想做的,它们太大而无法放入缓存,以合理的数量计算。所以你要么看看你在那些对象中如此频繁地操作是什么,并且只将它存储在容器中,要么你忍受不可避免的减速。如果您首先在 class 或您使用的结构中定义最重要的成员,您也可以加快速度,因为这转化为成员存储在内存中的布局。 class 会员的第一要务。
但正如所有这些人所建议的,更重要的是:通常您的算法复杂性对您编程的总体 运行 时间更为重要。
例如:问问你自己,你的程序是否在每个大对象上做一点工作然后转到下一个,然后才对每个大对象做一些其他小工作,这是非常低效的,或者你能做所有工作吗?一次获取一个对象,然后才转到下一个大对象?如果不是,为什么你的对象这么大?它们不应该只包含手头任务所需的东西吗?
不要为了希望事情会变得更快而把事情搞得一团糟。 "Premature optimization is the root of all evil" 是一个流行的引用是这个上下文。首先编写您的程序清晰易读且正确。然后 运行 它并测量它实际慢的地方。关于缓存实现的一般推测通常不是很有帮助,像 "When in doubt use a vector or array as they are usually the fastest" 这样的启发式就足够了。
或者为了更好地回答你的问题:std::array
和 std::vector
都是缓存友好的最佳选择,但是没有容器可以对大对象进行缓存友好,因为大对象因为大而对缓存不友好。
我知道 std::array 是缓存友好的,因为存储在 std::array 中的所有项目都紧密地排列在一起。如果我遍历数组,当我尝试访问一个项目时,CPU 会 预取 接下来的几个项目。
这就是我的困惑所在:通常 XEON 缓存行是 64 字节:即 8 int64_t 。成像我有
std::array<BigObject, 100>
其中每个 BigObject 的大小为 512 字节。在那种情况下,即使所有 BigObject 项目都彼此相邻打包,CPU 也无法做任何聪明的事情:它仍然必须逐行获取缓存,即每个 BigObject 8 行。因此,应该没有任何缓存友好的优势。
那么我的问题是:对于std::array大对象,是否还有缓存友好的优势?如果是这样,为什么?
澄清一下,处理器高速缓存的加速源于这样一个事实,即当今计算机的 RAM(即内存)比 CPU 慢几倍。所以 CPU 有一些小的内部存储器,所谓的缓存,速度很快。为了最好地利用小内存,CPU通常使用时间和space的概念,意思是经常使用的东西保存在缓存中,最近使用的东西旁边的东西,它们的邻居在内存,也被加载到缓存中,因为接下来很可能需要它们。
正如您所理解的那样,当事物在内存中紧密相连时,它们会被友好地缓存。由于 std::array
和 std::vector
被称为 ContiguousContainer,它们在内存中将它们的内容相邻保存。
因此,缓存友好确实可以将您经常一起使用的东西保存在一起,即您在循环中迭代或在这样的容器中一个接一个地使用。
如果你的对象像你说的那么大,你可以做你想做的,它们太大而无法放入缓存,以合理的数量计算。所以你要么看看你在那些对象中如此频繁地操作是什么,并且只将它存储在容器中,要么你忍受不可避免的减速。如果您首先在 class 或您使用的结构中定义最重要的成员,您也可以加快速度,因为这转化为成员存储在内存中的布局。 class 会员的第一要务。
但正如所有这些人所建议的,更重要的是:通常您的算法复杂性对您编程的总体 运行 时间更为重要。 例如:问问你自己,你的程序是否在每个大对象上做一点工作然后转到下一个,然后才对每个大对象做一些其他小工作,这是非常低效的,或者你能做所有工作吗?一次获取一个对象,然后才转到下一个大对象?如果不是,为什么你的对象这么大?它们不应该只包含手头任务所需的东西吗? 不要为了希望事情会变得更快而把事情搞得一团糟。 "Premature optimization is the root of all evil" 是一个流行的引用是这个上下文。首先编写您的程序清晰易读且正确。然后 运行 它并测量它实际慢的地方。关于缓存实现的一般推测通常不是很有帮助,像 "When in doubt use a vector or array as they are usually the fastest" 这样的启发式就足够了。
或者为了更好地回答你的问题:std::array
和 std::vector
都是缓存友好的最佳选择,但是没有容器可以对大对象进行缓存友好,因为大对象因为大而对缓存不友好。