GolangEP06:关于map-下
引子 上一篇文章中留下了两个问题没有解决 map 如何扩容 为什么原生的 map 线程不安全 其实这两个问题是有联系的,所以这篇文章来解决这两个问题。 map 的扩容机制 本节还是需要用到上一篇文章中的底层 hmap 结构 ...
引子 上一篇文章中留下了两个问题没有解决 map 如何扩容 为什么原生的 map 线程不安全 其实这两个问题是有联系的,所以这篇文章来解决这两个问题。 map 的扩容机制 本节还是需要用到上一篇文章中的底层 hmap 结构 ...
引子 在做两数之和时,操作 map 遇到了问题,可以看我下面的代码。 func twoSum(nums []int, target int) []int { sMap := make(map[int]int) for i, x := range nums { sMap[x] = i } var ans []int for i, y := range nums { // 如果另一个值在 map 中存在的话即下标大于等于 0;且要保证不能使用两次相同的元素 p := sMap[target-y] if p >= 0 && p != i { ans = append(ans, i) ans = append(ans, p) break } } return ans } 像极了一个 golang 新手的操作,特别是在判断 key 是否存在于哈希表中时,用值(下标)是否大于 0 来判断。(当然前面的哈希表的定义也有问题) ...
引子 在使用 Go 语言开发过程中,我发现经常会遇到想使用的项目的 Go 版本与当前本机的 Go 版本不一致的情况,通常是本地的版本较低。 所以每次都需要去手动更新版本,而手动更新的过程是比较繁琐的,需要下载新版本并替换旧版本(听起来也没什么是吧)但是 Go 版本的更新还算是比较频繁的,特别是各种小版本。 ...
引子 之前的两篇文章关于context和channel,我们都从源码的角度去讨论了其各自的底层原理以及使用方法。 但是我并没有从宏观的角度上来阐述为什么我们需要并发?为什么要设计这两种结构来处理并发,本着做到"what-how-why"的态度,我们今天来深入讨论一下 Go 中的并发。 ...
引子 字符串操作在任何语言中的地位都十分重要,在上篇关于 Golang 中特殊的切片讲完之后,这一次我准备进入 Golang 中字符串的底层世界,包括引用总结自<100 Go Mistakes and How to Avoid Them (Teiva Harsanyi)> 书籍的注意事项。 ...
引子 在做力扣的题目时,特别是遇到递归问题,需要传入参数,遇到切片的时候经常遇到需要克隆切片的情况,而遇到普通的int类型的时候却不需要。 显而易见,这是一个值传递还是引用传递的问题,所以今天我来总结一下 Golang 中切片的底层原理,为什么在递归中需要克隆它。 ...
前言 让我们看看关于 chan 有哪些常见的操作。 创建channel ch1 := make(chan int) ch2 := make(chan int, 2) 底层实际上调用的是makechan方法 发送数据到channel ch <- 1 底层实际调用的是chansend1,而chansend1最终也是调用chansend,将block参数设置为true——当前发送操作是阻塞的 从channel中读取数据 i <- ch i, ok <- ch 底层实际调用的是chanrecv1和chanrecv2,最终都去调用了chanrecv。 源码 接下来我们进入源码中一探究竟。 hchan结构体 type hchan struct { qcount uint // total data in the queue dataqsiz uint // size of the circular queue buf unsafe.Pointer // points to an array of dataqsiz elements elemsize uint16 synctest bool // true if created in a synctest bubble closed uint32 timer *timer // timer feeding this chan elemtype *_type // element type sendx uint // send index recvx uint // receive index recvq waitq // list of recv waiters sendq waitq // list of send waiters // lock protects all fields in hchan, as well as several // fields in sudogs blocked on this channel. // // Do not change another G's status while holding this lock // (in particular, do not ready a G), as this can deadlock // with stack shrinking. lock mutex } qcount:通道中存储的数据元素总数 dataqsiz:环形队列大小 buf:执行环形队列的内存缓冲区,存放实际数据——环形缓存区域,本质上是一个带有头尾指针的固定长度的数组 sendx,recvx:发收操作的队列位置 recvq,sendq:等待队列 可以发现,hchan 使用环形队列表示缓冲区并且采用 lock 确保并发访问的安全性。 ...
引子 今天心血来潮,给自己梳理梳理golang中这个十分重要的东东——context,毕竟也是在面试中考察到,但是反问自己的时候却感觉一点也说不出来什么有价值的东西,所以今天我来一次刨根究底。 ...