Go源码版本1.13.8
系列导读
本系列基于64位平台、1Page=8KB
前言
是的,我也是一个PHPer,对于我们PHPer转Gopher的银????,一定有个困扰:Go语言里每次遍历Map输出元素的顺序并不一致,但是在PHP里却是稳定的。今天我们就来看看这个现象的原因。
本文目录如下:
Go的Map遍历结果“无序”
-
遍历Map的索引的起点是随机的
Go的Map本质上是“无序的”
-
无序写入
-
正常写入(非哈希冲突写入)
哈希冲突写入
扩容
-
成倍扩容迫使元素顺序变化
等量扩容
Go的Map遍历结果“无序”
现象:Go语言里每次遍历Map输出元素的顺序并不一致,但是在PHP里却是稳定的。
关于这个现象我就不过多赘述了,同时我相信大家应该都网上搜过相关的文章,这些文章大多都说明了原因:For ... Range ... 遍历Map的索引的起点是随机的,没错,就是下面这段代码。
// versions/1.13.8/src/cmd/compile/internal/gc/range.go
func walkrange(n *Node) *Node {
// 略...
// 遍历Map时
case TMAP:
// 略...
// 调用mapiterinit mapiterinit函数见下方
fn := syslook("mapiterinit")
// 略...
fn = syslook("mapiternext")
// 略...
}
// versions/1.13.8/src/runtime/map.go
func mapiterinit(t *maptype, h *hmap, it *hiter) {
// 略...
// 对,就是这行代码
// 随机一个索引值,作为遍历开始的地方
// decide where to start
r := uintptr(fastrand())
if h.B > 31-bucketCntBits {
r += uintptr(fastrand()) << 31
}
// 略...
mapiternext(it)
}
但是呢,有没有再推测过Go的作者们这么做背后的真正原因是什么?个人觉着因为:
Go的Map本质上是“无序的”
Go的Map本质上是“无序的”,为什么这么说?