Go语言工程实践 | 青训营

77 阅读2分钟

二、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框架,生成索引,构建路由,启动服务