为什么遍历 Go map 是无序的?原生map为什么是非线程安全的?

简介: 为什么遍历 Go map 是无序的?原生map为什么是非线程安全的?

 参考:大佬文章

一、为什么遍历 Go map 是无序的?

代码层原因:

for range map 在开始处理循环逻辑的时候,就做了随机播种,用于决定从哪里开始循环迭代。更具体的话就是根据随机数,选择一个桶位置作为起始点进行遍历迭代。

image.gif编辑

结果:

因此每次重新 for range map,你见到的结果都是不一样的。那是因为它的起始位置根本就不固定!

根本原因:

你想问为什么要这么做?当然是官方有意为之,因为官方在 Go 早期的时候,发现很多工程师都较依赖 map 的遍历迭代顺序。但这将会导致可移植性存在问题。因此,改之。也请不要依赖...

二、go语言为什么不在语言层面保证map线程安全?

Golang1.9版本后,增加了并发安全的sync.Map。相比原生map加互斥锁的解决方案,性能稍微高一点。去读下代码,就知道这个东西虽然也用了锁,但还是做了一些优化。至于原生map为什么不是并发安全,这个很好理解。并发安全是有代价的。如果原生map保证并发安全,那么一些不需要并发的场景,会有不小的性能损耗

      一个常见的场景,比如你在函数内无并发需求,仅需要一个临时map存kv,也用加锁的map么? 嗯,开销有些大了。所以,原生map就单纯实现map基础就好了。要安全,加锁。(分并发场景来就行~)

三、map如何判断某个key在map中是否存在?

map通过hash值的高8位和低8位来快速判断key是否存在,并通过返回ok值判断。参考文章~

目录
相关文章
|
3月前
|
Go
go语言中遍历映射(map)
go语言中遍历映射(map)
87 8
|
18天前
|
存储 安全 Go
Go语言中的map数据结构是如何实现的?
Go 语言中的 `map` 是基于哈希表实现的键值对数据结构,支持快速查找、插入和删除操作。其原理涉及哈希函数、桶(Bucket)、动态扩容和哈希冲突处理等关键机制,平均时间复杂度为 O(1)。为了确保线程安全,Go 提供了 `sync.Map` 类型,通过分段锁实现并发访问的安全性。示例代码展示了如何使用自定义结构体和切片模拟 `map` 功能,以及如何使用 `sync.Map` 进行线程安全的操作。
|
4月前
|
存储 安全 算法
Go语言是如何支持多线程的
【10月更文挑战第21】Go语言是如何支持多线程的
127 72
|
2月前
|
Go
go语言for遍历映射(map)
go语言for遍历映射(map)
62 12
|
3月前
|
存储 Go
go语言 遍历映射(map)
go语言 遍历映射(map)
55 2
|
4月前
|
Go 调度 开发者
Go语言多线程的优势
【10月更文挑战第15天】
37 4
|
4月前
|
前端开发 小程序 Java
java基础:map遍历使用;java使用 Patten 和Matches 进行正则匹配;后端传到前端展示图片三种情况,并保存到手机
这篇文章介绍了Java中Map的遍历方法、使用Pattern和matches进行正则表达式匹配,以及后端向前端传输图片并保存到手机的三种情况。
46 1
|
5月前
|
Go 定位技术 索引
Go 语言Map(集合) | 19
Go 语言Map(集合) | 19
|
2月前
|
NoSQL Redis
单线程传奇Redis,为何引入多线程?
Redis 4.0 引入多线程支持,主要用于后台对象删除、处理阻塞命令和网络 I/O 等操作,以提高并发性和性能。尽管如此,Redis 仍保留单线程执行模型处理客户端请求,确保高效性和简单性。多线程仅用于优化后台任务,如异步删除过期对象和分担读写操作,从而提升整体性能。
70 1
|
4月前
|
存储 消息中间件 资源调度
C++ 多线程之初识多线程
这篇文章介绍了C++多线程的基本概念,包括进程和线程的定义、并发的实现方式,以及如何在C++中创建和管理线程,包括使用`std::thread`库、线程的join和detach方法,并通过示例代码展示了如何创建和使用多线程。
77 1