Code Monkey home page Code Monkey logo

goexpertprogramming's Introduction

《GO专家编程》

图书介绍

本书涵盖内容:

  • 常见数据结构、控制结构的实现原理剖析;
  • 常用标准库实现原理剖析;
  • 工具链使用、原理剖析(如 Go test、Go Module等);
  • 编程陷阱及相关真实案例解析;

纸质版

致谢

本书写作过程中,得到了广大读者的支持和鼓励,作者本人也很高兴本书能够帮助到读者。

读者鼓励:

  • @Wang-Kai:

这一定是我在 Github 发现的最有价值的仓库之一。

  • @liyonglion:

感谢贡献如此好文,结合你的文章,再看源码如虎添翼。

  • @li-keli:

首先,确实如你所说 是让初级进阶的文档 下午github摸鱼看到这个库,草草阅读后,发现挖掘到了宝藏。 忍不住收藏细细的再多读几遍。 我读过基本Go的书,比如《Go实战》《Go并发编程》,对比之下,此文档也是干货满满,从目录看,直击我这种3年以内经验人的痛点,只会用,只会写项目,但是不理解底层,不理解实现,写不出高性能项目,可能遇到问题都不知道如何快速排查。 其实我目前这种层次的人不是不知道问题所在,只是手头的资料并没有系统化,都很碎。 市面上的go中文书籍或者文档都比较基础,官方文档一方面是英文,有些阅读障碍,另一方面,有部分确实比较难懂。

热心读者

部分热心读者提交了大最PR帮助作者修复书中错误,在此向这些读者表示感谢:

  • @marjune163
  • @twz915
  • @xiaoxuanzi
  • @weiyuanke
  • @wangdayong228
  • @notech
  • @li-keli
  • @hjlarry
  • @exqlnet
  • Bingao-hn

特别感谢@marjune163帮忙修复了大量错误,本书出版后,特向@marjune163寄送了一本纸质书,聊表谢意。

后续

鉴于本仓库内容与纸质图书已有相当大的差异,也考虑到出版社的利益,暂时下架部分章节,待与出版社沟通后再陆续放出。

goexpertprogramming's People

Contributors

bingao-hn avatar exqlnet avatar hjlarry avatar marjune163 avatar notech avatar rainbowmango avatar twz915 avatar wangdayong228 avatar weiyuanke avatar xiaoxuanzi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

goexpertprogramming's Issues

5.2 章节疑问

Add()操作必须早于Wait(), 否则会panic

这个理论怎么来的?

func main() {
	var wg sync.WaitGroup

	wg.Wait()
	wg.Add(2)
}

wo我这边尝试了一下没有得到任何 panic 啊

输出是正常的

image

[勘误]反馈一个第一章第2节的错别字

问题描述
image
位置:第一章->1.2 Slice -> 3.5特殊切片
这里的对最后一个值的解读不太对,最后一个值应该是max。还有新切片的容量应该是cap = max - low;


这是我从网上找的一本PDF,不确实最新版本或者纸质书里面有没有这个问题

关于第四章2.2节中的疑问

第四章2.2节中提到 alloc为mspan的指针数组,数组大小为class总数的2倍。数组中每个元素代表了一种class类型的span列表 其中数组中的每个元素代表span列表怎么理解呢?我理解是每个元素只能代表一个span

[勘误]反馈一个第1章第3节的内容错误

问题描述
网页版的内容有点小问题

如何找到这个错误

  • 章节:1
  • 页码:1.3

您认为应该如何?
map扩容确实是渐进式扩容,但是每次搬迁时并不是搬迁两个键值对,而是尝试搬迁两个bucket
图片
image

其他补充信息
源代码里面,通过evacuate函数进行实际的搬迁,并且是进行线性遍历,会对与每个bucket及其链接的所有overflow bucket都会进行搬迁,所有并不仅仅是两个键值对

[勘误]反馈一个第一章第一节的错误

问题描述
第一章 1.1 节的 4.2 select 中提到 select 对于读是不阻塞的,以下是原文:

通过这个示例想说的是:select的case语句读channel不会阻塞,尽管channel中没有数据。这是由于case语句编译后调用读channel时会明确传入不阻塞的参数,此时读不到数据时不会将当前goroutine加入到等待队列,而是直接返回。

但示例中的 select 不阻塞其实是因为加了 default 吧,如果不加 default 的话还是会阻塞的,参考如下代码:

ch := make(chan int, 10)
go func() {
	time.Sleep(time.Second)
	ch <- 1
}()

select {
case n := <-ch:
	fmt.Println("ch read:", n)
}

fmt.Println("select read...")

如何找到这个错误

  • 章节:第一章:常见数据结构实现原理
  • 页码:1.1 节

您认为应该如何?
select 不加 default 的话,读 channel 是会阻塞的,加了 default,就走 default 不阻塞了。

图片
image

其他补充信息
(无)

[勘误] 关于3.2G0系统调用描述问题探讨

问题描述
3.2G0系统调用描述错误
image

如何找到这个错误

  • 章节:3
  • 页码:

您认为应该如何?

这一小段是否描述为m0被系统调用更为合理,尽管本质上也是系统调用了G0,但描述上是否应该以m0视角出发

图片
如果有可能,尽量提供图片。

其他补充信息

关于3.2G0系统调用描述问题探讨

问题描述
关于3.2G0系统调用描述问题探讨

516BAF96-41EF-4951-A9C5-1BD0826D9670

如何找到这个错误

  • 章节:3
  • 页码:

您认为应该如何?

这一小段是否描述为m0被系统调用更为合理,尽管本质上也是系统调用了G0,但描述上是否应该以m0视角出发
仅代表个人观点,如果说的不对的话还望见谅

图片
如果有可能,尽量提供图片。

其他补充信息

疑问关于 4.2 内存分配

第2节提到

spans区域存放span的指针,每个指针对应一个page

但是之后的说法都是每个span管理着一个或多个page,是否有矛盾?

调试手段素材征集

[root@ecs-d8b6 ~]# go tool trace
Usage of 'go tool trace':
Given a trace file produced by 'go test':
	go test -trace=trace.out pkg

Open a web browser displaying trace:
	go tool trace [flags] [pkg.test] trace.out

Generate a pprof-like profile from the trace:
    go tool trace -pprof=TYPE [pkg.test] trace.out

[pkg.test] argument is required for traces produced by Go 1.6 and below.
Go 1.7 does not require the binary argument.

Supported profile types are:
    - net: network blocking profile
    - sync: synchronization blocking profile
    - syscall: syscall blocking profile
    - sched: scheduler latency profile

Flags:
	-http=addr: HTTP service address (e.g., ':6060')
	-pprof=type: print a pprof-like profile instead
	-d: print debug info such as parsed events

Note that while the various profiles available when launching
'go tool trace' work on every browser, the trace viewer itself
(the 'view trace' page) comes from the Chrome/Chromium project
and is only actively tested on that browser.

延伸阅读:

Typo category

  • 跟据 --> 根据
  • 些时 --> 此时
  • 任意的 --> 任意地
  • 不断的 --> 不断地
  • 起动 --> 启动
  • 做为 --> 作为 (根本没有'做为'的用法)
  • 显式的 --> 显式地

关于13.1节的疑问

感觉13.1节的内容跟13.3节有冲突,因为13.3节解释到append时值传递所以不可能操作原来的slice。那13.1节的扩容分析感觉不是问题所在,即使不扩容,只要不接收返回返回值,原来的slice也不会变化。

[勘误]反馈一个第5章第3节的context描述错误

问题描述
在介绍context的时候,对于 context.Done() 是这样描述的

当context关闭后,Done()返回一个被关闭的管道,关闭的管道仍然是可读的,据此goroutine可以收到关闭请求,当context还未关闭时,Done()返回nil

显然最后一句是不妥的,Done只可能会返回nil,参考下面原文。

如何找到这个错误

  • 章节:5.3 context
  • 页码:121

您认为应该如何?

Done may return nil if this context can never be canceled.

原文

// Done returns a channel that's closed when work done on behalf of this
// context should be canceled. Done may return nil if this context can
// never be canceled. Successive calls to Done return the same value.
// The close of the Done channel may happen asynchronously,
// after the cancel function returns.

建议的修改

无论context取消与否,context.Done() 总会返回同一个只读的管道,
这个管道会在context被取消时关闭。区别在于,context取消后,返回的管道是已经关闭的。
需要注意的是:如果当前context不支持取消,Done()可能会返回nil。例如, context.Backgroud()。
对于一个 nil chan,select语句会直接忽略这个分支,但如果对 nil chan 直接进行读写则会导致当前goroutine永远阻塞。

图片
如果有可能,尽量提供图片。

其他补充信息

很早之前发现了这么一本开源书籍,觉得很棒加了收藏夹,最近在造轮子的时候又想参考一些内容,结果点开404才愕然发现出了书。
白嫖失败所以第二天就在京东下单买了😂
个人觉得内存管理和GC部分是对我帮助最大的一块,尤其是堆内存分配机制这块,讲的很棒。
最近刚刚读过 The Journey of Go's Garbage Collector,对GC Pacer这块还不是很理解具体细节,不知道作者是否有兴趣讲解一二。

另外感觉本书可以增补的一些部分,struct padding(memory alignment/wasted byte),memory model(happens before),atomic都是很有意思的内容。前者对于了解struct内存布局,reflect offset等hack操作都很有帮助,后者可以加深对于同步机制的理解,或是帮助使用一些基于指令级别的“无锁”操作。

[勘误]反馈一个第1章第2节,关于切片简单表达式的 cap 取值问题

问题描述
A clear and concise description of what the bug is.
切片的简单表达式中 cap 值计算表达式有误

如何找到这个错误

  • 章节:第1章第2节,1.2.4 切片表达->1.简单表达式->1)底层数组共享
  • 页码:P22

您认为应该如何?
在书中写道:

新切片的生成逻辑可以使用以下伪代码表示:

b.array = &a[low]
b.len = high - low
b.cap = len(a) - low

应该是:b.cap = cap(a) - low ,b 的 cap 是由 a 的 cap 而不是 len 计算出来的

图片
如果有可能,尽量提供图片。
image

其他补充信息

[勘误]反馈一个第4章 4.1内存分配的配图问题

问题描述

WechatIMG26
这本书对进阶非常有帮助,谢谢了。
95页关于 Go 程序启动时向系统申请的内存配图,bitmap 的大小是 512GB,我看了挺多资料,包括作者您网上开源的版本,都是根据 bitmap 中1个 byte 大小的内存对应 arena 区域中 4 个指针大小(指针大小为 8B)的内存,所以 bitmap 区域的大小 512G /(4*8B) = 16GB

如何找到这个错误

  • 章节:第四章
  • 页码:95

您认为应该如何?

图片
如果有可能,尽量提供图片。

其他补充信息

想请教一下作者这个 bitmap 分配 512 GB 是怎么计算的呢?谢谢

感谢读者发现纰漏

尊敬的作者:
您好!我正在阅读您的《GO专家编程》一书,书中的内容很有价值,我学习到了很多 go 语言的内部实现。
我在阅读 2.5 rwmutex 这一章节时,我发现了一处错误,通过与 go 源代码和 github 仓库中的图进行核对,
我认为:图中的 RWMutex.w.Lock() 应该是 RWMutex.w.Unlock()

略去相关截图与读者姓名

[勘误]反馈一个第1章第3节的错别字

问题描述
A clear and concise description of what the bug is.
哈希冲突解决错误描述有误

如何找到这个错误

  • 章节:1 章 3 节 -> 1.3.3 实现原理 -> 2. Hash 冲突
  • 页码:P30

您认为应该如何?
原句:"由于每个 bucket 可以存放 8 个键值对,所以同一个 bucket 存放超过 8 个键值对时就会再创建一个键值对,用类似链表的方式将 bucket 连接起来"
认为有误的地方:"同一个 bucket 存放超过 8 个键值对时就会再创建一个 bucket?",创建的是 bucket,通过 overflow 指针连起来,而不是再创建一个"键值对"吧?

图片
如果有可能,尽量提供图片。

其他补充信息

[勘误]反馈一个第1章第3.3节的流程图

image

从buf队首取出数据,再从sendq取出一个G,图片红框应该是把数据写入到G吧?然后唤醒g,而不是又把G的数据写入到队尾,难道是带着数据来的G?

谢谢

[勘误]反馈一个第2章第2节的错别字

问题描述
A clear and concise description of what the bug is.
关于字符和字节的错误使用

如何找到这个错误

  • 章节:2 章 2 节 -> 2.2 for-range ->2.2.2 特性速览 -> 3. 作用于 string
  • 页码:P79

您认为应该如何?
在 P79 中间部分关于 rune 类型的描述中,原句为:
"另外需要注意的是,range 的第二个返回值的类型为 rune 类型,它仅代表 Unicode 编码的 1 个字节"
想请教老师这的 "字节" 是否使用不当,应当为 "字符"
个人理解是,例如:

  • 'h',这是一个字符,占一个字节
  • '中',这是一个字符,占三个字节

不知是否理解有误,请老师斧正

图片
如果有可能,尽量提供图片。

其他补充信息

关于13.1节的疑问

问题描述
感觉13.1节的内容跟13.3节有冲突,因为13.3节解释到append时值传递所以不可能操作原来的slice。那13.1节的扩容分析感觉不是问题所在,即使不扩容,只要不接收返回返回值,原来的slice也不会变化。

[勘误]反馈一个第1章第3节的问题

问题描述
hmap.bucket为数组指针,数组的大小为2^B,例如:hmap.B=2, 而hmap.buckets长度是2^B为4

增量扩容内容当中,这个 B=1, 应该是 B=0 吧,不然应该是有两个bucket
image

还有这个地方,这个 B=2 , 应该是 B=1
image

希望大佬解答疑惑

[内容优化] 图片形式

问题描述
Hi.
书看了一半有余,觉得内容都很独特新颖,感谢分享。

关于书中图片有一些小建议,目前(应该是)所有插图都是标量图,看起来都是在类似ProcessOn这类工具上画出来再保存(png | jpg等)下来,然后插入到正文中的,在阅读的时候就会发现图中的中英文、图形、箭头都有模糊不清。尽管没有影响到理解内容,但是观感上来说对图书而言还是觉得可以改善。

您认为应该如何?
插图使用矢量图。但是全书内容重新编辑可能工作量也比较大,不然的话陈晓猛老师应该也有考虑过这个问题,在出版前处理掉了。

其他补充信息
Ver: 2020年7月第一版第1次印刷。
最后感谢任老师的写作,内容很棒。

[建议] 5.3 context可以把例子前移么

我注意到大部分的章节都是先用一些例子起篇,这样可以帮助读者先建立一个直观的理解。但不知道为什么5.3 context却先从实现原理入手,然后再给出例子。这样对于我这种对context都不了解的人会看的云里雾里。作者这里是有什么特殊的考量么?

[勘误] 反馈热身测验题目选项有误

问题描述
热身测验题目选项有误

如何找到这个错误

  • 章节:第八章 / 8.2 defer / 8.2.1 热身测验 / 题目二
  • 页码:227

您认为应该如何?
下面函数的输出结果是什么(单选)?

func DeferDemo2() {
        var aInt = 1

        defer fmt.Println(aInt)

        aInt = 2
        return
}
  • A: 0
  • B: 1

应改为:

  • A: 2
  • B: 1

图片
如果有可能,尽量提供图片。

其他补充信息

[勘误]反馈一个第2章第2.3节的错别字

问题描述
勘误, web 版可能的typo, 位置: 题目三,参考答案, 最后一句 “”循环次效“” 应改为 “循环次数“”

如何找到这个错误

  • 章节:2.3
    题目三,参考答案, 最后一句循环

您认为应该如何?

图片
如果有可能,尽量提供图片。

其他补充信息

Example测试疑似bug

源码:

func RangeString() {
	s := "Hello World"
	for i, v := range s {
		fmt.Printf("index: %d, value: %c\n", i, v)
	}
}

Example:

func ExampleRangeString() {
	RangeString()
	// Output:
	// index: 0, value: H
	// index: 1, value: e
	// index: 2, value: l
	// index: 3, value: l
	// index: 4, value: o
	// index: 5, value:
	// index: 6, value: W
	// index: 7, value: o
	// index: 8, value: r
	// index: 9, value: l
	// index: 10, value: d

结果:

--- FAIL: ExampleRangeString (0.00s)
got:
index: 0, value: H
index: 1, value: e
index: 2, value: l
index: 3, value: l
index: 4, value: o
index: 5, value:
index: 6, value: W
index: 7, value: o
index: 8, value: r
index: 9, value: l
index: 10, value: d
want:
index: 0, value: H
index: 1, value: e
index: 2, value: l
index: 3, value: l
index: 4, value: o
index: 5, value:
index: 6, value: W
index: 7, value: o
index: 8, value: r
index: 9, value: l
index: 10, value: d

如果字符串中包含空格,测试将失败。原因未明。

[勘误]反馈一个第2章第2节的错别字

问题描述
“由于string底层使用 Unicode 编码方式,字符可能占用1-4个字节”,

如何找到这个错误

  • 章节:2.2.2特性预览
  • 页码:P78

您认为应该如何?

应该是UTF8

图片
如果有可能,尽量提供图片。

其他补充信息

goroutine 调度疑问

感谢开源出这么好的文章,这一定是我在 Github 发现的最有价值的仓库之一。

在协程调度一文 3.1 队列轮转 中,有提到如下观点:

上图中可见每个P维护着一个包含G的队列,不考虑G进入系统调用或IO操作的情况下,P周期性的将G调度到M中执行,执行一小段时间,将上下文保存下来,然后将G放到队列尾部,然后从队列中重新取出一个G进行调度。

文中的观点是 P 存在有类似时间片的调度机制,不管 G 是否执行完毕,会把它重新放入队列,再取出新的 G 执行。

但我在另外一篇文章中又读到

Once a runnable G is found, it is executed until it is blocked.

P 会一直执行 G,直到 G 处于阻塞状态。

求作者答疑,解决我的困惑。

[勘误]反馈一个第2章第2.2节的示例运行结果错误

问题描述
slice原理一节的2.2示例的运行结果和解释错误。

如何找到这个错误

  • 章节:2.2 题目二
  • 页码:

您认为应该如何?
false

图片
如果有可能,尽量提供图片。

其他补充信息

示例的源代码:

package main

import (
"fmt"
)

func AddElement(slice []int, e int) []int {
return append(slice, e)
}

func main() {
var slice []int
slice = append(slice, 1, 2, 3)

newSlice := AddElement(slice, 4)
fmt.Println(&slice[0] == &newSlice[0])

}

错误原因:
因为AddElement函数内部append重新扩容了,但是它和原来的slice是两个内存地址值。

注:我的golang 1.16.7版本

请教下移除timer为何采用四叉堆实现呢 ?

type runtimeTimer struct {
	tb uintptr
	i  int

	when   int64
	period int64
	f      func(interface{}, uintptr) // NOTE: must not be closure
	arg    interface{}
	seq    uintptr
}

用数组实现, 移除(还未过期)的时候可以直接根据数组下标定位到对应的堆元素, 时间复杂度 O(1), 然后调整堆顺序 O(lgN)

我有两个问题:

  1. 为什么要用四叉堆呢?
  2. 如果不用数组实现的话, 移除元素有什么数据结构能达到 O(lgN) 的时间复杂度吗?

[勘误]反馈一个第一章第二节中关于slice扩容问题

问题描述
文中描述是基于go1.16之前版本扩容规则,1.16后扩容规则有所变动。题目举例已经不符合预期了。

func main(){
 var slice []int
 slice = append(slice, 1, 2, 3)// 此时cap(slice)为3,go1.16前为4
}

如何找到这个错误

  • 章节:
    常见数据结构实现原理中slice篇
  • 页码:

您认为应该如何?

图片
如果有可能,尽量提供图片。

其他补充信息

Gopher

浏览了你的开源书,还有开源社区的贡献,发现你不仅参与kubernetes & CNCF 比较多,而且对Go语言也有极大的研究热情,可以留个邮箱交流下吗?

timer.Stop() 返回值的解释貌似有误

https://github.com/RainbowMango/GoExpertProgramming/blob/master/chapter09/9.1.2-timer_principle.md#%E5%81%9C%E6%AD%A2timer

Timer还未触发,系统协程已经删除该Timer,Stop()返回false;
Timer已经触发,系统协程还未删除该Timer,Stop()返回true;

https://golang.google.cn/pkg/time/#Timer.Stop

It returns true if the call stops the timer, false if the timer has already expired or been stopped.

可能是这样的?

  • Timer还未触发,且系统协程还未删除该Timer,Stop()返回true
  • Timer已经触发,或系统协程已经删除该Timer,Stop()返回false

管道部分增加一个有趣的试题

func ReadChanReturnValue() {
	ch := make(chan int, 10)
	ch <- 1
	ch <- 2
	fmt.Printf("length of channel is: %d\n", len(ch))

	_, ok := <-ch
	fmt.Printf("second return value before channel closed is: %v\n", ok) // true

	close(ch)

	_, ok = <-ch
	fmt.Printf("second return value after channel(have data) closed is: %v\n", ok) // true

	_, ok = <-ch
	fmt.Printf("second return value after channel(no data) closed is: %v\n", ok) // false
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.