gpt4 book ai didi

c - 循环内的函数,或函数内的循环

转载 作者:太空宇宙 更新时间:2023-11-04 04:47:32 25 4
gpt4 key购买 nike

简单地说,以下哪一项可能是更好的选择:

somestruct data[lots];
for(int i=0;i<lots;i++) {
a(&data[i]);
b(&data[i]);
c(&data[i]);
}
//....
void a(somestruct* d) { ..stuff with d.. }
void b(somestruct* d) { ..stuff with d.. }
void c(somestruct* d) { ..stuff with d.. }

somestruct data[lots];
a(lots,data);
b(lots,data);
c(lots,data);
//...
void a(int n, somestruct* d) {
for(int i<n;i++) {
..stuff with d[i]..
} }
void b(int n, somestruct* d) {
for(int i<n;i++) {
..stuff with d[i]..
} }
void c(int n, somestruct* d) {
for(int i<n;i++) {
..stuff with d[i]..
} }

我的理解是,对于 A,当前事件的结构将被缓存,从而得到改进,但会有一大堆函数调用(负面)。另一方面,对于 B,我将丢弃我的缓存,但有 3 个函数调用,而不是 3*lots 函数调用。

如果我的编译器决定内联 a、b 和 c,那么第一个选项应该是最佳选择(因为我们现在拥有两全其美),但我的感觉是,在大多数情况下,如果它没有,函数调用的成本远高于内存访问。

我知道唯一知道的方法是对我的特定应用程序进行基准测试,但很好奇是否有任何我在这里遗漏的经验法则。第一个版本为我的特定案例生成了更简洁的代码,但差别不大。

编辑

我想问一个问题,即进入函数的成本(分配堆栈指针和其他任何东西)与缓存未命中的成本相比如何。我认为通用答案也可能对其他人有用。然而,问题的一般形式似乎无法得到令人满意的回答,所以这里是完整的统计数据,假设我算对了:

  • 数据是 100,000 个结构,每个结构包含六个 double 和一个整数。
  • a() 是六个双读、三个双乘、三个双加和三个双存储。
  • b() 是三个双读、三个双乘、四个加、两个双比较和有条件地调用 c。
  • c() 是三个双倍乘法、三个函数调用和三个双倍写入。

最佳答案

您应该问的主要问题是函数调用和内存访问(尤其是缓存未命中)之间的区别是什么。如果数据结构很大(大到缓存无法容纳),就会有一些缓存未命中。在您提供的第一种情况下,这些缓存未命中将重复 3 次,而在第一种情况下,它们只会发生一次。此外,函数可以按每 10 个元素的顺序访问数据结构。这将增加高速缓存未命中的次数。如果数据结构足够小,就不会有缓存未命中,函数调用开销将接管(如果编译器没有内联它们)。但是,一般来说,您不能假定要分析的数据结构的大小,所以我会选择第一个解决方案,使问题保持​​一般性。在某些特定情况下,第二种解决方案可能更好。

关于c - 循环内的函数,或函数内的循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19470633/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com