Go1.23 迭代器慢到令人发指!

package main

import (
	"maps"
	"slices"
	"testing"
)

//使用三种不同的方式实现把map的key元素转换成slice

// BenchmarkSdkIter 使用go1.23新的迭代器实现
func BenchmarkSdkIter(b *testing.B) {
	mp := make(map[int]int)
	for i := range 50000 {
		mp[i] = i
	}
	b.ResetTimer()
	for range b.N {
		_ = slices.Collect(maps.Keys(mp))
	}
}

func Keys[K comparable, V any](in map[K]V) []K {
	result := make([]K, 0, len(in))

	for k := range in {
		result = append(result, k)
	}

	return result
}

// BenchmarkGeneric 使用泛型
func BenchmarkGeneric(b *testing.B) {
	mp := make(map[int]int)
	for i := range 50000 {
		mp[i] = i
	}
	b.ResetTimer()
	for range b.N {
		_ = Keys(mp)
	}
}

func keys(maps map[int]int) []int {
	keySlice := make([]int, 0, len(maps))
	for k := range maps {
		keySlice = append(keySlice, k)
	}
	return keySlice
}

// BenchmarkRawForLoop使用最原始的办法
func BenchmarkRawForLoop(b *testing.B) {
	mp := make(map[int]int)
	for i := range 50000 {
		mp[i] = i
	}
	b.ResetTimer()
	for range b.N {
		_ = keys(mp)
	}
}

测试结果
在这里插入图片描述

结果即在意料之中又在意料之外
意料之中的是 for loop 稍快于 泛型 快于 go1.23新的迭代器
意料之外的是go1.23的迭代器居然慢了这么多,速度只有for loop 的一半

很乐意看到go团队终于实现了go迭代器的统一,但是这个效果真的不尽人意。仔细分析原因其实也很清楚,go1.23的迭代器中有大量的回调函数,
简单理解:
1.使用原生的for loop相当于只有1个 50000的循环
2.使用泛型也是只有1个50000的循环,但是每次迭代比for loop 多了一次解引用
3.1.23的迭代器就不一样了,除了1次50000的循环,每次迭代都是一次函数回调的过程,而且slices.Collect还不能预申请内存,自然要慢非常多了

参考
1.https://www.gingerbill.org/article/2024/06/17/go-iterator-design/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值