go性能优化 #
10亿级for循环 #
获取一个整数5000,然后生成一个随机数,接着通过两层循环对一个数组的每个元素进行累加,最终输出该数组中以随机数为下标对应的数组元素的值。
func Test_one(t *testing.T) {
input := 5000
u := int32(input)
r := int32(rand.Intn(10000))//使用更快的rand实现
var a [10000]int32 //固定大小数组,栈上分配内存 避免逃逸
for i := int32(0); i < 10000; i++ {
for j := int32(0); j < 10000; j++ {
a[i] = a[i] + j%u
}
a[i] += r
}
fmt.Println(a[r])
return
}
=== RUN Test_one
25004351
--- PASS: Test_one (0.14s)
PASS
将数组元素累积到一个临时变量中,并在外层循环结束后写回数组,这样做可以减少内层循环中的内存读写操作,充分利用CPU缓存和寄存器,加速数据处理。
func Test_two(t *testing.T) {
input := 5000
u := int32(input)
r := int32(rand.Intn(10000))
var a [10000]int32
for i := int32(0); i < 10000; i++ {
tem := a[i]
for j := int32(0); j < 10000; j++ {
tem += j % u
}
tem += r
a[i] = tem
}
fmt.Println(a[r])
return
}
=== RUN Test_two
25000245
--- PASS: Test_two (0.08s)
PASS
循环展开(Loop Unrolling) 是一种常见的优化技术,用于提高程序的执行效率,特别是在循环体内的计算是独立的,并且计算次数很大时。它的主要目的是减少循环中的控制开销和提高指令级并行性。
原理
循环展开的基本思想是通过增加每次循环迭代中的工作量,从而减少循环的控制结构开销。具体来说,就是将一个循环体分解成多个较小的循环体,从而减少每次迭代时的条件判断和跳转操作,进而减少分支预测的失败和减少执行周期。
通过展开循环,程序每次执行多个迭代的内容,而不是一个一个地执行,通常会减少对循环控制变量的更新、跳转指令等操作。
func Test_three(t *testing.T) {
input := 5000
u := int32(input)
r := int32(rand.Intn(10000))
var a [10000]int32
for i := int32(0); i < 10000; i++ {
tem := a[i]
for j := int32(0); j < 10000; j += 4 {
tem += j % u
tem += (j + 1) % u
tem += (j + 2) % u
tem += (j + 3) % u
}
tem += r
a[i] = tem
}
fmt.Println(a[r])
return
}
=== RUN Test_three
24996369
--- PASS: Test_three (0.07s)
PASS