这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天
Go语言进阶
一、Go并发编程
1、线程与协程
- 线程属于内核态由操作系统调度 开启及关闭线程都是重型操作
- 协程属于用户态由Go语言开启 一个线程可以同时运行多个协程
- Go语言可同时开启几万个协程(Go语言适合高并发的原因)
2、并发与并行
- 并发:多线程程序在单核CPU上运行(通过时间片控制)
- 并行:多线程程序在多核CPU上运行
3、Go语言开启协程
在函数前加go即可开启协程
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
go say("world")
say("hello")
}
4、协程通信的两种方式
- 通过通信共享内存(Go语言中的主要方式)
- 通过共享内存实现通信(Go语言仍然保存 通过加互斥锁实现 会影响效率)
5、Channel
通道(channel)是用来传递数据的一个数据结构。
通道可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯。操作符 <- 用于指定通道的方向,发送或接收。如果未指定方向,则为双向通道。
带缓冲的channel可以解聚生产者消费者处理速率不均衡带来的效率问题
package main
import (
"sync"
"time"
)
var (
x int64
lock sync.Mutex
)
func addWithLock() {
for i := 0; i < 2000; i++ {
lock.Lock()
x += 1
lock.Unlock()
}
}
func addWithoutLock() {
for i := 0; i < 2000; i++ {
x += 1
}
}
func main() {
x = 0
for i := 0; i < 5; i++ {
go addWithLock()
}
time.Sleep(time.Second)
println("add withlock:", x)
x = 0
for i := 0; i < 5; i++ {
go addWithoutLock()
}
time.Sleep(time.Second)
println("add withoutlock:", x)
}
二、Go依赖管理
Gopath
缺点:不同模块依赖同一个包但依赖版本不同时会出现版本问题
GoVendor
缺点:同一个项目依赖不同包时 会有代码冲突问题
GoModule
解决了Gopath与GoVendor的问题 定义了版本规则与管理项目依赖关系
依赖管理三要素
Proxy
Proxy会将代码托管平台的依赖进行缓存,实现了可靠稳定的依赖管理,避免了对第三方代码托管平台的大流量访问
GoProxy环境变量设置
资源查找顺序 先到Proxy1 再到 Proxy2 都找不到后回到源站找
Goget
可以拉取不同版本的依赖 默认拉取master分支的依赖
Gomod
每次执行项目之前都可以执行以下 go tidy
三、Go 语言工程实践之测试
如果评价项目的测试水准
代码覆盖率 一般覆盖率50%~60% 重要功能需要到80%
单元测试的两个目标稳定、幂等
基准测试
对代码进行性能分析
四、项目实践
1、需求描述
- 展示话题和回帖列表
- 仅实现后端服务
- 数据存储在文件中
2、项目创建
web框架:Gin - github.com/gin-gonic/g…