Language agnostic 直接访问数组元素与将其分配给变量

Language agnostic 直接访问数组元素与将其分配给变量,language-agnostic,performance,Language Agnostic,Performance,就性能而言,是“直接”多次访问数组元素更好,还是将其值赋给变量并使用该变量更好?假设我将在下面的代码中多次引用该值 这个问题背后的原因是,每次访问数组元素时,可能会涉及一些计算成本,而不需要额外的空间。另一方面,将值存储在变量中可以消除这种访问成本,但会占用额外的空间 // use a variable to store the value Temp = ArrayOfValues(0) If Temp > 100 Or Temp < 50 Then Dim Blah = T

就性能而言,是“直接”多次访问数组元素更好,还是将其值赋给变量并使用该变量更好?假设我将在下面的代码中多次引用该值

这个问题背后的原因是,每次访问数组元素时,可能会涉及一些计算成本,而不需要额外的空间。另一方面,将值存储在变量中可以消除这种访问成本,但会占用额外的空间

// use a variable to store the value
Temp = ArrayOfValues(0)
If Temp > 100 Or Temp < 50 Then
    Dim Blah = Temp
    ...

// reference the array element 'directly'
If ArrayOfValues(0) > 100 Or ArrayOfValues(0) < 50 Then
    Dim Blah = ArrayOfValues(0)
    ...
//使用变量存储值
Temp=ArrayOfValues(0)
如果温度>100或温度<50,则
暗布拉赫=温度
...
//直接引用数组元素'directly'
如果ArrayOfValues(0)>100或ArrayOfValues(0)<50,则
Dim Blah=阵列值(0)
...

我知道这是一个很小的例子,但假设我们讨论的是实际使用中的更大范围(该值将被多次引用),那么在什么情况下,空间和计算时间之间的折衷值得考虑(如果有的话)?

内存消耗的开销非常有限,因为对于引用类型来说,它只是一个指针(几个字节)并且大多数值类型也只需要几个字节

数组在大多数语言中都是非常有效的结构。获取索引不需要任何查找,只需要一些数学运算(每个数组槽需要4个字节,因此第11个槽的偏移量为40)。那么边界检查可能会有一点开销。为新的本地变量分配内存并释放它也需要一点cpu周期。因此,最后还取决于通过复制到本地变量来消除多少数组查找

事实上,你真的需要非常糟糕的硬件,或者有非常大的循环,这才是真正重要的,如果在上面运行一个像样的测试,我个人经常选择单独的变量,因为我发现它使代码更易于阅读

顺便说一句,您的示例很奇怪,因为您在创建本地变量之前进行了2次数组查找:) 这更有意义(再查找两次)

Dim blah=ArrayOfValue(0)
如果blah>100或blah<50,则
...

这被标记为语言不可知论,但我真的不相信这是真的。这个帖子回答了问题的C和C++版本。 优化编译器可以处理“裸”数组访问;在C或C++中,如果没有调用函数,编译器就不可能记住内存位置的值。例如

int a = myarray[19];
int b = myarray[19] * 5;
int c = myarray[19] / 2;
int d = myarray[19] + 3;
但是,如果myarray不仅定义为int[],而且实际上是“花哨”的,特别是在另一个转换单元中定义了函数
运算符[]()
的用户定义的容器类型,那么每次请求该值时都必须调用该函数(因为函数返回内存中某个位置的数据,而本地函数不知道函数的结果是常量)

即使使用“裸”数组,如果您在函数调用前后多次访问同一个对象,编译器也同样必须假定值已更改(即使它可以记住地址本身)

编译器不可能知道myarray[19]在函数调用前后具有相同的值

因此,一般来说,如果知道某个值在局部范围内是常量,请将其“缓存”在局部变量中。您可以进行防御性编程,并使用断言来验证您在某些方面设置的条件:

int a = myarray[19];
NiftyFunction();
assert(myarray[19] == a);
int b = a * 8;

最后一个好处是,如果调试器中的值没有隐藏在某个数组中,则更容易检查它们。

优化编译器将使这一点对HLL完全没有意义。如果您正在使用汇编或关闭优化,则寄存器比缓存快,因此您应该将经常使用的值作为m加载到寄存器中这是可能的。一般来说,我认为语域压力和记忆等级之间的转折点可能是一个经验问题。+1表示“这是标记语言不可知论,但我并不真的认为它是。”C的答案在某些方面可能会有所不同,但我没有资格提供它。
int a = myarray[19];
NiftyFunction();
int b = myarray[19] * 8;
int a = myarray[19];
NiftyFunction();
assert(myarray[19] == a);
int b = a * 8;