二、Go并发
1.协程goroutine
协程:轻量级线程。线程位于内核态,栈为MB级别,协程位于用户态,栈为KB级别。在函数前加上go,即可为函数创建协程,实现并发
package main
import(
"fmt"
"time"
)
func hello(j int){
fmt.Println(j)
}
//使用匿名函数创建一个闭包,将参数i传给闭包,然后这个闭包在一个goroutine中被调用,异步执行hello函数
func main(){
for i:=0;i<5;i++{
go func(j int){
hello(j)
}(i)
}
//使当前的goroutine暂停1秒钟
time.Sleep(time.Second)
}
//输出
2
3
4
0
1
2.CSP通信
CSP(Communicating Sequential Processes,通信顺序进程)是一种并发模型,主要思想是两个goroutine通过channel通道进行通信,实现数据共享,比共享内存(需要设置互斥量加锁)性能要高。
channel通道:无缓冲通道make(chan int),发送和接收同步;有缓冲通道make(chan int,2),可以异步,类似生产者消费者模型。使用<-来将数据发送到通道中
package main
import(
"fmt"
)
func CalSquare(){
src:=make(chan int)//发送通道
dst:=make(chan int,3)//接收通道
go func(){
defer close(src)
for i:=0;i<10;i++{
src <- i //将i发送到src通道中
}
}()
go func(){
defer close(dst)
for i:=range src{
dst <- i*i //将i*i发送到dst通道中
}
}()
for i:=range dst{
fmt.Println(i)
}
}
func main(){
calSquare()
}
3.Sync
加锁Lock:为保证共享内存时并发安全,需要将对临界区的访问加锁,使用变量lock sync.Mutex,加锁lock.Lock(),解锁lock.Unlock()
waitgroup计数器
三、依赖管理
$GOPATH:包含
- bin:编译产生的二进制文件
- pkg:编译的中间文件
- src:项目源码。但如果两个项目需要一个package的不同版本,就会冲突
Go Vender:项目下增加vender目录,存放package副本。但如果两个package依赖于一个package的不同版本还会冲突
Go Module:一个类似maven的包管理控制系统
- 在go.mod配置文件中描述依赖和版本号。非直接依赖使用indirect后缀。版本格式:
${MAJOR}:${MINOR}:${PATCH},同一major下的版本兼容 - Proxy:缓存保证依赖稳定分发
go get example.org/pkg拉取依赖- go mod init <模块名>:初始化go.mod文件 go mod download下载模块到本地缓存 go mod tidy清理不需要的依赖
四、测试
1.单元测试
规范:测试文件以_test.go结尾,函数TestXxx(t *testing.T),在TestMain函数中初始化
使用t.Errotf打印错误,也可使用assert.Equal(t,expectOutput,output)
代码覆盖率:在编译时加上--cover,计算 测试用例对代码的覆盖度,比如一个用例在执行时经过了2行代码,一共3行,那么覆盖度就是2/3。一般覆盖率在五六成,八成较高。
2.Mock测试
一般的单元测试中,对于一个本地测试文件有预期输出,和运行结果比较即可,但这样很依赖于测试文件,如果修改了就没法测试了。
mock测试:对函数打桩,用打桩函数替代原函数,打桩函数中模拟了测试对象,使得测试时不需要依赖本地的测试对象文件。monkey包
3.基准测试
benchmark:测试CPU性能和损耗,代码执行n次串行计算时间,或RunParallel并行测试
五、工程方法
项目分层
- 数据层Repository:数据Model,增删改查
- 逻辑层Service:业务Entity,处理核心业务逻辑
- 视图层Controller:视图View,与前端的接口
Gin框架:添加Gin依赖go get gopkg.in/gin-gonic/gin.v1@v1.3.0
实现两个API:根据topic id查主题;根据topic id查文章pos。topic和post都是结构体。
- 视图层:接收来自前端的id参数,转为int传给service
- 逻辑层:将id发给数据层去查询;根据数据层返回的数据,处理不同error,返回页面
- 数据层:通过Map数据结构建立索引,topic=map[id]
Gin负责搭建web框架,生成索引,构建路由,启动服务