Git Product home page Git Product logo

chai2010 / advanced-go-programming-book Goto Github PK

View Code? Open in Web Editor NEW
19.1K 550.0 3.2K 24.17 MB

:books: 《Go语言高级编程》开源图书,涵盖CGO、Go汇编语言、RPC实现、Protobuf插件实现、Web框架实现、分布式系统等高阶主题(完稿)

Home Page: https://chai2010.cn/advanced-go-programming-book/

License: BSD 2-Clause "Simplified" License

Makefile 5.51% Go 7.37% Assembly 2.12% JavaScript 18.72% CSS 4.79% Handlebars 61.49%
go golang book cgo asm rpc web cloud

advanced-go-programming-book's Issues

附录中对“Goroutine饿死”相关知识的表述不准确

附录go坑章节中讲到:
“Goroutine是协作式调度, Goroutine本身不会主动放弃CPU”
这种表叙并不准确。网上很多类似的表述。

个人认为比较准确的表述:
“G-P-M模型的实现算是Go scheduler的一大进步,但Scheduler仍然有一个头疼的问题,那就是不支持抢占式调度,导致一旦某个G中出现死循环或永久循环的代码逻辑,那么G将永久占用分配给它的P和M,位于同一个P中的其他G将得不到调度,出现“饿死”的情况。更为严重的是,当只有一个P时(GOMAXPROCS=1)时,整个Go程序中的其他G都将“饿死”。于是Dmitry Vyukov又提出了《Go Preemptive Scheduler Design》并在Go 1.2中实现了“抢占式”调度。

这个抢占式调度的原理则是在每个函数或方法的入口,加上一段额外的代码,让runtime有机会检查是否需要执行抢占调度。这种解决方案只能说局部解决了“饿死”问题,对于没有函数调用,纯算法循环计算的G,scheduler依然无法抢占。”
源自:https://tonybai.com/2017/06/23/an-intro-about-goroutine-scheduler/

ch3 汇编语言 开工

  1. 目录调整(Done)
  2. 第一节, 快速入门(Done)
  3. 第二节, 计算机结构(Done)
  4. 第三节, 常量和变量(Done)
  5. 第四节, 函数(Done)
  6. 第五节, 控制流(Done)
  7. 第六节, 再论函数(Done)

PS: 我也是汇编新手,如果大家发现错误,欢迎指出!非常感谢

关于 6.3 middleware 的一个问题

Expected Behavior

实际上只要你的 handler 函数签名是:

func (ResponseWriter, *Request)

那么这个 handler 就是一个 HandlerFunc 类型了,也就相当于实现了 http.Handler 这个接口,这要归功于 golang 的 duck typing 式的类型系统。

Actual Behavior

如果我的 handler 函数签名是:

func(ResponseWriter, *Request)

并不能证明这个 handler 就是一个 HandlerFunc 类型,也并不是相当于实现了 http.Handler 这个接口。若想让自己的函数作为 http.Handler 接口类型使用,需要使用 http.HandlerFunc() 转换类型。

appendix 有误

appendix中appendix-a-trap.md 内存地址会变化部分,
unsafe.Poiner
应为
unsafe.Pointer

ch1-03 的一些建议

其中有一段描写删除开头元素的文字。

a = []int{1, 2, 3}
a = append(a[:0], a[1:]...) // 删除开头1个元素
a = append(a[:0], a[N:]...) // 删除开头N个元素

我觉得一般读者在读到这里的时候,肯定会疑惑,为啥不使用下面这段代码,至少看上去会更简洁,平时也会去使用。

a = a[1:]
a = a[N:]

如果能加上两者的比较,我觉得会有更大的帮助。
下面是我写的一个简单的测试代码

a := []int{1, 2, 3, 4, 5, 6, 7, 8}

h1 := (*reflect.SliceHeader)(unsafe.Pointer(&a))
fmt.Println(h1)
fmt.Println((unsafe.Pointer)(h1))
fmt.Println((*int)((unsafe.Pointer)(h1.Data)))

b := a[5:]
h2 := (*reflect.SliceHeader)(unsafe.Pointer(&b))
fmt.Println(h2)
fmt.Println((unsafe.Pointer)(h2))
fmt.Println((*int)((unsafe.Pointer)(h2.Data)))

c := append(a[:0], a[5:]...)
h3 := (*reflect.SliceHeader)(unsafe.Pointer(&c))
fmt.Println(h3)
fmt.Println((unsafe.Pointer)(h3))
fmt.Println((*int)((unsafe.Pointer)(h3.Data)))

"完成"应该是"完整"

1.1. Go语言创世纪 中的倒数第二段中的"完成"应该是"完整"

Expected Behavior

" 最终这些package再有机地组成一个完整的Go语言程序 "

Actual Behavior

" 最终这些package再有机地组成一个完成的Go语言程序 "

个人意见 ^_^

请教和建议

1 Golang 的源代码已经支持 BOM 头的 utf8 文件

2 原文:错误编码不会向前扩散是UTF8编码的优秀特性之一
疑点:这个看起来应该是 “向后” 扩散,不过这可能是我们对 “前”,“后” 理解的不同

3 原文:因为Go线程的启动是非阻塞的, main 线程显式休眠了1秒钟退出 导致程序结束,我们可以近似地认为程序总共执行了1秒多时间。现在假设 println 函数内部 实现休眠的时间大于 main 线程休眠的时间的话,就会导致矛盾:后台线程既然先于 main 线 程完成打印,那么执行时间肯定是小于 main 线程执行时间的。当然这是不可能的。
疑点:这句话觉得比较拗口,读了几遍也不大理解

4 原文:对于带缓冲的Channel,对于Channel的第K个接收完成操作发生在第K+C个发送操作完成之 前,其中C是Channel的缓存大小。
疑点:这句话容易让用户觉得,接收完成操作是在缓存满了之后开始。实际上,缓存的 Channel,不管 C 长度多少,只要有接收和发送,都是立即开始的。举个例子,一个 Channel 长度 100,send 和 receive 的 Goroutine 都在运行,那么可以说 send 1,然后 receive 1

开源宣言

为何要开源,有哪些原因,如何看待开源的风险

命名规范

明确章节文件名, 引用的图片文件名等命名规则

附录中对"不同Goroutine之间不满足顺序一致性内存模型"的举例不恰当

我自己理解的附录中的例子(见最下方) 发生的问题是在它之上描述的独占CPU导致其它Goroutine饿死的问题

当在for 循环中加入runtime.Gosched()来使程序正常结束

觉得例子不是很恰当

var msg string
var done bool = false

func main() {
    runtime.GOMAXPROCS(1)

    go func() {
        msg = "hello, world"
        done = true
    }()

    for {
        if done {
            println(msg)
            break
        }
    }
}

因为要准备cgo报告, asm部分暂缓

GopherChina2018 要准备一个 《深入CGO编程》的报告,asm部分暂时没有精力准备。

cgo报告的内存比目前cgo的章节内容更加丰富,因此在报告初稿完成后会对cgo章节进行一次修订(但不是最终的修订),补充缺少的内容。

对cgo感兴趣的同学可以关注下,cgo中有许多烧脑的问题欢迎你来一起探讨。

报告最终也会放到网上。

ch1-06-goroutine 小bug

生产者消费者小节

func Producer(factor int, out chan<- int) {
	for i := 0; ; i++ {
		item <- i*factor  // 这里应该是 out <- i*factor
	}
}

// 消费者
func Consumer(in <-chan int) {
	for _, v := range in { //这里应该是 for v := range in {
		fmt.Println(v)
	}
	go Consumer(ch)    // 消费 生成的队列

	// Ctrl+C 退出
	ch := make(chan os.Signal, 1) //这里的二次初始化也是笔误,希望代码还是能直接跑比较好
	signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
	fmt.Printf("quit (%v)\n", <-ch)

开发环境增加 docker 说明

基于 docker 的编译环境优势:

  • 保持环境一致
  • 跨平台开发(macos/windows下开发linux应用)
  • docker镜像可以同时打包辅助工具(比如swig/protoc/swagger等工具)

ch1-04 上的一些疑问?

这一章提到第二个函数

内部虽然调用new函数创建了*int类型的指针对象,但是依然不知道它具体保存在哪里

func f(x int) *int {
	return &x
}

func g() int {
    x := new(int)
    return *x
}

运行上面的代码,两者的地址都可以看到。请问第二个函数不知道它具体保存在哪里具体指的是什么意思?谢谢。

ch1-05-mem.md中,顺序一致性内存模型 部分 有误

ch1-basic章
ch1-05-mem.md中,顺序一致性内存模型 部分

“当然,通过sync.Mutex互斥量也是可以实现同步的”下面的代码段:

go func(){
	println("你好, 世界")
	mu.Unock()
}()

应该为:
go func(){
println("你好, 世界")
mu.Unlock()
}()

少了l

vgo支持

所有例子要基于vgo编译,避免为当前 url 路径的依赖(太长了,fork后不能工作)

cgo: 增加编译和链接参数一节

  • CFLAGS/CPPFLAGS/CXXFLAGS
  • LDFLAGS
  • pkg-config
  • 自定义 pkg-config
  • go get 链
  • 多个非main包中导出C函数
  • go get 安全漏洞和白名单参数
  • cgo 交叉编译

1.4 函数定义问题

1.4中的函数Find定义是有点问题的。对于map[key]的返回值默认是一个,如果使用value, ok := map[key] 可以返回两个值,一个是key所对应的值,另一个是key在map中是否存在。但是如果使用return map[key], 只能返回value。所以 Find 函数需要改成

func Find(m map[int]int, key int) (value int, ok bool) {
	value, ok = m[key]
	return
}

writing error

Expected Behavior

chapter 1.3
string(bytes)转换模拟实现 函数中有个书写错误
for i, c := s should be replaced by for i, c := range s

Actual Behavior

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.