出于好奇,我一直在查看标准库中的sort
包和即将成为added to the standard library的实验slices
包的源代码.这两个包都定义了一个IsSorted
函数,它们通过验证相邻元素是否排序来判断列表是否排序.然而,这是在reverse年完成的.
我创建了一个小复制品,大致基于通用的slices
包.我的实验确实表明,reverse版的速度更快.
func IsSortedForward[T any](slice []T, compare func(a, b T) int) bool {
for i := 0; i < len(slice) - 1; i++ {
if compare(slice[i], slice[i+1]) > 0 {
return false
}
}
return true
}
func IsSortedForward2[T any](slice []T, compare func(a, b T) int) bool {
n := len(slice) - 1
for i := 0; i < n; i++ {
if compare(slice[i], slice[i+1]) > 0 {
return false
}
}
return true
}
func IsSortedReverse[T any](slice []T, compare func(a, b T) int) bool {
for i := len(slice) - 1; i > 0; i-- {
if compare(slice[i], slice[i-1]) < 0 {
return false
}
}
return true
}
我最初的 idea 是,向前版本会更"缓存友好".然而,我确实注意到反向版本的一个优点,因为len(slice) - 1
只计算一次.然而,在前向版本中,它是在每次迭代时计算的.我的假设是,这就是为什么反向版本略微快一些的原因.
然后,我在前向版本的循环外提取了len(slice) - 1
,因此只计算一次,这确实提高了它的性能.然而,它仍然比反向版本略微慢一些.我的猜测是,反向版本中的比较i > 0
(零)比向前版本中的比较i < n
更快?
Why do you think the reverse version is faster? Why is the adjusted forward version still not as fast as the reverse version?个
编辑:我不知道编译器资源管理器(Godbolt)可以和Go一起工作……这里是这个问题中涉及的little reproduction个函数.看来围棋有它自己的assembly language?