笔记:Lecture 5: Go, Threads, and Raft
视频:Lecture 5: Go, Threads, and Raft
论文地址:The design of a practical system for fault-tolerant virtual machines
课程概要
Go语言内存模型、并发原语、并发模式、调试
正文内容
Go内存模型这篇文章讲述go语言中的内存模型,它告诉我们如何写出正确的多线程代码。goroutines和并发在go中有着千丝万缕的关系,性能、便捷性。经过语言的不断迭代,goroutines的性能也得到极大的提升。本课的重点在于如何写正确的并发代码,而不是性能。
“write correct code”.
Goroutines,闭包
goroutines是轻量级线程,彼此并发运行。当main goroutine退出时,程序自动终止,与此同时程序运行的其他goroutines也会终止运行。
闭包:标示符捕获,gotchas绑定
- closure.go:go中拥有头等函数,配合goroutines使用。对变量的作用域进行限制,让声明的函数只作用域闭包内部。
- loop.go:循环创建goroutine(输出结果不一定按顺序输出,因为并发,并非同步执行)
- bad.go:变量i访问的是gorountine外部变量,每个goroutine访问时的结果都不确定,受外部循环执行快慢的影响。
Time
- sleep.go:time.Now()、time.Sleep()
- sleep-cancel.go:不要写无限循环的代码。使用锁时要小心死锁。函数返回(return)前需要释放锁
Mutexes:互斥量
- bad.go
- basic.go:基本使用defer
-
per-field.go:锁保护是保护变量,不是保护访问共享数据。锁的目的是为了在访问或者是修改变量时,只有单个线程在操作。其结果不受其他线程的影响。所以转账的增和减应在同一个锁里面。
关键:临时暂停其他线程的修改、unlock解锁访问。没有其他线程打断访问
锁:确保lock()与unlock之间的代码执行的原子性,防止竞争访问或者修改
- bank.go:银行转账问题
条件变量
- 等待(wait)、信号(signal)、广播(broadcast)
- vote-count-1.go ….vote-count-4.go
- cond.txt,如何避免竞争条件。
- 锁的使用
- 使用循环检查条件状态,也可以使用条件变量sync.Cond
- 锁应避免在会导致CPU100%的代码段中使用
Channel:通道
- 类似同步队列原语
- producor-consumer.go 生产消费者模型
- wait等待前置调用完成
- unbuffered.go:未初始化长度的通道,同步
- deadlock.go:死锁
Debugging:调试
- 在Raft目录下可以使用util.go中的DPrintf调试,输出日志
- 使用-race帮助识别数据竞争
- go test -race -run 2A
- not a proof
- race不是万能的,不是所有的竞争数据情况都能识别到
- SIGQUIT
- SIGQUIT默认监听所有的goroutines.并打印栈
- Ctrl+\可以发送SIGQUIT到当前进程
- 处理goroutines溢出
- 使用ps命令查看运行的进程
- 发送SIGQUIT或者是SIGKILL信号给进程:kill -QUIT pid 或 kill -KILL pid
- 并行
- 同时跑多个测试用例可以更轻松的发现一些并发bug
- Script for running go tests many times in parallel, printing the current status, and logging errors
常用工具
- 使用man命令查看工具使用的手册
- 或者使用tldr命令快速的查看手册:tldr.sh
- 重定向输出
- stdout输出正常结果
- stderr输出错误结果
>
、&>
- 重定向输出结果到文件,错误会接着显示
- & 错误和标准输出都写入到文件
- tee、通道
|
、|&
- tee重定向输出到文件并显示
echo "example" | tee FILE
- 使用
|&
可以重定向标准输出和错误
- 文件阅读
- head、tail、less
- grep
- -i不区分大小写
- -n显示行号
- grep -in searchString file
- ripgrep Ripgrep
- 和grep类似,但支持整个目录
参考资料
- The Go Memory Model
- Go 并发代码
- 頭等函數
- Visualizing Concurrency in Go
- Go Concurrency Patterns: Pipelines and cancellation
- Go Concurrency Patterns: Timing out, moving on