go性能优化

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

百万任务场景下内存开销大的“问题” #