当前位置:网站首页>Source code analysis of golang map concurrent read / write problem
Source code analysis of golang map concurrent read / write problem
2022-06-27 19:56:00 【Lynalmost】
map Introduction and problem description
map It's mainly used to store kv data , The bottom layer uses the open chain method to eliminate conflicts hashtable, It has an automatic capacity expansion mechanism . Use map The most convenient thing is that you can O(1) A quick query ( at present slice No query interface is provided , You can only write your own algorithm to determine whether an element exists ).
map Although easy to use , But it may not apply .
however map There is a very deadly pit , In a concurrent scenario , Concurrent reading / Writing may occur fatal error:concurrent map read and map write Error of , Just beginning to use map At the time of the naive that as long as not the same key Concurrent operation is OK , But it's a reality . There may be no problem when the concurrency is very small during testing ( Just lucky ), A large amount of concurrency will cause problems .
But not in all scenarios map It's not safe
This is a golang Official documents of , As mentioned above, as long as there is an update operation ,map It's non thread safe , But if the usage scenario is just concurrent reading , Write not involved / Delete operation , So it is concurrency safe .
Source code analysis
Definition
map head in flags Field , Recorded the current map Some states of , among hashWriting Is to cause concurrent reading and writing map Wrong report “ The culprit ”.
// A header for a Go map.
type hmap struct {
// Note: the format of the hmap is also encoded in cmd/compile/internal/gc/reflect.go.
// Make sure this stays in sync with the compiler's definition.
count int // # live cells == size of map. Must be first (used by len() builtin)
flags uint8
B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
noverflow uint16 // approximate number of overflow buckets; see incrnoverflow for details
hash0 uint32 // hash seed
buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacuated)
extra *mapextra // optional fields
} // flags
iterator = 1 // there may be an iterator using buckets
oldIterator = 2 // there may be an iterator using oldbuckets
hashWriting = 4 // a goroutine is writing to the map
sameSizeGrow = 8 // the current map growth is to a new map of the same sizewrite in
- towards map The new element in the will eventually call
mapassignfunction , It will be checked before the new operationflagsOfhashWritingWhether a is 1, by 1 May be an error . - After passing the inspection, the position will be set as 1, The tag is currently being written .
- After writing, set the position to 0
// Like mapaccess, but allocates a slot for the key if it is not present in the map.
func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
...
if h.flags&hashWriting != 0 {
throw("concurrent map writes")
}
hash := t.hasher(key, uintptr(h.hash0))
// Set hashWriting after calling t.hasher, since t.hasher may panic,
// in which case we have not actually done a write.
h.flags ^= hashWriting
...
done:
if h.flags&hashWriting == 0 {
throw("concurrent map writes")
}
h.flags &^= hashWriting
...Read
The process of reading data is relatively simple , Before reading, determine whether there is a setting , If the verification is passed, the read operation can be performed , The read operation will not be set .
That's why , If one map Initialized ok after , As long as there is no addition, deletion or modification , Read the newspaper incorrectly at the same time .
// mapaccess1 returns a pointer to h[key]. Never returns nil, instead
// it will return a reference to the zero object for the elem type if
// the key is not in the map.
// NOTE: The returned pointer may keep the whole map live, so don't
// hold onto it for very long.
func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
...
if h.flags&hashWriting != 0 {
throw("concurrent map read and map write")
}
...
}Conclusion
1. After reading the source code , I found it was like a read-write lock , But it doesn't cause any blockage , If there's a problem, it's direct throw.
2. If you do initialize once , Always read concurrently , You can use it boldly map.
Common solutions
1. Self lock read .
2. Use sync.map replace ( I've seen some principles , Locking is implemented when writing data ; Using space for time , Use two hash structures to store Map, There is a layer of cache , Speed up data reading .)
3. Use 2D slice instead of , take key and index Mapping .
# If there is any misunderstanding or misunderstanding ~ Welcome to correct ~~
边栏推荐
- MySQL beginner benefits
- 作为软件工程师,给年轻时的自己的建议(下)
- openssl客户端编程:一个不起眼的函数导致的SSL会话失败问题
- Leetcode 821. 字符的最短距离(简单) - 续集
- Observable, reliable: the first shot of cloudops series Salon of cloud automation operation and maintenance
- Crontab's learning essays
- 从指令交读掌握函数调用堆栈详细过程
- Kotlin微信支付回调后界面卡死并抛出UIPageFragmentActivity WindowLeaked
- 谈谈线程安全
- One week technical update express of substrate and Boca 20220425 - 20220501
猜你喜欢

带你认识图数据库性能和场景测试利器LDBC SNB

Array exercises follow up

429- binary tree (108. convert the ordered array into a binary search tree, 538. convert the binary search tree into an accumulation tree, 106. construct a binary tree from the middle order and post o

什么是SSR/SSG/ISR?如何在AWS上托管它们?

A simple calculation method of vanishing point

MySQL初学者福利

Blink SQL内置函数大全

Redis持久化
![[login interface]](/img/72/d527a5de23aa9da108e405eb6bb39c.png)
[login interface]

The Fifth Discipline: the art and practice of learning organization
随机推荐
(LC)46. Full Permutation
Leetcode 989. 数组形式的整数加法(简单)
binder hwbinder vndbinder
通过 Cargo 管理 Rust 项目
RANSAC的代码和原理
键入网址到网页显示,期间发生了什么?
Solution of adding st-link to Huada MCU Keil
Implementation of reliable distributed locks redlock and redisson
shell脚本常用命令(四)
DCC888 :Register Allocation
Embracing cloud Nativity: Practice of Jiangsu Mobile order center
《第五项修炼》(The Fifth Discipline):学习型组织的艺术与实践
中金证券经理给的开户二维码安全吗?找谁可以开户啊?
指针和结构体
UE4随笔:FString、FName 与 FText
什么是SSR/SSG/ISR?如何在AWS上托管它们?
Bit. Store: long bear market, stable stacking products may become the main theme
UE4-Actor基础知识
数组练习 后续补充
MySQL beginner benefits