C++ 对于包含指向结构的指针的链表,性能与“如何”之间是否存在任何关系;“大”;结构是什么?
只是好奇在迭代/访问列表中的对象时是否对性能有任何影响。我想假设不会有什么不同,但还是很好奇 例子: VSC++ 对于包含指向结构的指针的链表,性能与“如何”之间是否存在任何关系;“大”;结构是什么?,c++,c,performance,struct,singly-linked-list,C++,C,Performance,Struct,Singly Linked List,只是好奇在迭代/访问列表中的对象时是否对性能有任何影响。我想假设不会有什么不同,但还是很好奇 例子: VS 第二种情况可以更快,如果您像这样分配内存:一个结构靠近另一个。因此,CPU可以将一些结构读入单个缓存线。取决于如何分配节点 如果从内存池中分配节点,使节点具有较高的局部性,则较小的节点允许更多节点装入CPU缓存或内存页,这将降低缓存未命中和页面错误的频率 如果节点没有高局部性,那么大小对于列表的迭代并不重要。当为每个节点使用全局分配器(即std::malloc)时,可能会出现这种情况 要了
第二种情况可以更快,如果您像这样分配内存:一个结构靠近另一个。因此,CPU可以将一些结构读入单个缓存线。取决于如何分配节点 如果从内存池中分配节点,使节点具有较高的局部性,则较小的节点允许更多节点装入CPU缓存或内存页,这将降低缓存未命中和页面错误的频率 如果节点没有高局部性,那么大小对于列表的迭代并不重要。当为每个节点使用全局分配器(即
std::malloc
)时,可能会出现这种情况
要了解它是否对您的计划有显著影响,您可以对其进行测量
另外,如果您关心性能,则链表很有可能不是适合您的最佳数据结构。如果结构足够小,可以在缓存线中容纳多个结构,则可以实现最佳性能,并且分配的方式使得在彼此访问之后不久的结构实际上将被放置在相同的缓存线中 如果结构比缓存线大得多,则可以通过确保经常连续访问的结构部分彼此靠近来实现最佳性能 考虑以下三种结构:
struct s1 { struct s1 *next; int dat[1000]; int x,y; };
struct s2 { struct s1 *next; int x,y; int dat[1000]; };
struct s3 { struct s1 *next; int x,y; int *dat; };
由以下循环访问:
while(p->x)
p = p->next;
第二种方法的性能可能比第一种方法要好得多,因为第一种方法在循环的大多数迭代中会导致两次缓存未命中,而第二种方法只会导致一次缓存未命中。如果较小的大小允许结构彼此靠近,则在处理上述循环时,第三个循环的性能可能比第二个循环更好(每次迭代可能导致平均不到一次缓存未命中),但在访问dat
(因为在使用第二种形式时,将结构放入缓存也会引入dat
的前几个元素,但在使用第三种形式时则不会)
请注意,除非是在“真实世界”下完成,否则性能基准可能具有欺骗性条件。
struct s2
在大多数实际条件下的性能不太可能比s1
差,但是s2
和s3
之间的相对性能可能会受到外部代码所做工作的细微变化的显著影响。如果您分配了大量小结构
s in快速连续。如果在这两者之间有其他分配,那么它们可能同样零碎。你说:“这重要吗?”。在什么意义上重要?对不起,我指的是从列表遍历的角度来看的性能编辑标题——不管结构有多大或多小。列表包含的只是指向节点的指针。该节点可以包含1个字符和->next
指针,也可以包含1024个成员的结构——指针仍然只是一个点呃。在create node函数中,您必须分配并初始化所有结构成员,而在其他任何函数中,您必须操作结构成员。但是,这本身与基本遍历的速度无关。如果您根据内存资源进行推理,很明显,在第一种情况下,y你将消耗更多的资源。从CPU方面看,这取决于部分//做一些事情如果你在结构中有更多的元素,你可能会做更多的事情,因此你将消耗更多的CPU。关于side=temp->next
;没有变化,无论你的next
指向1字节还是100mo,它都被简化为指针增量测量它?@scottc11使用时钟测量程序运行所需的时间。将程序更改为使用更大的节点,然后再次测量。重复测量几次,并使用统计数据确定是否存在显著差异。基准测试有许多微妙之处,因此对结果持保留态度。@eerorik答:在现代系统中,有意义的基准测试已经变得非常困难,因为外部代码所做的细微变化可能会对性能产生巨大影响。例如,如果一个分配器碰巧将大小为1.5缓存线的对象与半缓存线边界对齐,并且一个程序分配了多对1.5缓存线对象但是每对中的对象使用方式不同,哪些对象开始于缓存线边界的问题可能会对性能产生巨大影响。
struct s1 { struct s1 *next; int dat[1000]; int x,y; };
struct s2 { struct s1 *next; int x,y; int dat[1000]; };
struct s3 { struct s1 *next; int x,y; int *dat; };
while(p->x)
p = p->next;