Go语言入门-工程实践摘要 | 青训营笔记

113 阅读2分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第2篇笔记。

并发编程

并发与并行的区别:并发是多线程程序在一个核的CPU上运行,并行是在多个核的CPU上运行。一个线程包括多个协程。在go中使用goroutine实现并发编程,只需要在函数方法前添加go即可并发执行,独立于主线程之外,提倡通过通信共享内存而不是共享内存而实现通信。

下个例子中可以通过加锁来避免并发冲突。

var (
   x   int64
   lock  sync.Mutex
)

func main() {
   add()
}

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 add() {
   x=0
   for i := 0; i < 5; i++ {
      go addWithOutLock()
   }
   time.Sleep(time.Second)
   fmt.Println("不加锁的条件下,执行完之后的x:",x)
   x=0
   for i := 0; i < 5; i++ {
      go addWithLock()
   }
   time.Sleep(time.Second)
   fmt.Println("加锁的条件下,执行完之后的x:",x)
}

执行结果为:

image.png 可以看到不加锁的时候x明显漏了很多,说明并发量大的时候会产生线程冲突。造成数据遗漏。除了采用加锁的方式也可采用waitgroup。

依赖管理

1、go vender

解决多个项目需要依赖同一个package依赖的冲突问题,但无法控制依赖的版本,更新项目可能会出现依赖冲突。

2、go module

即常用的go mod init \ go get 等

image.png 版本选择上会选择最低的兼容版本。

单元测试

单元测试可以不启动整个项目,来单独测试某一个功能,或者整个项目出现bug之后,通过单元测试快速查找bug位置。

func TestHelloTom(t *testing.T) {
   output := HelloTom()
   expect := "Tom"
   if output != expect {
      t.Error(expect,output)
   }
   println("success")
}

和Java中的spring-boot-starter-test依赖类似

func HelloTom() string {
   return "Tom"
}

测试分支相互独立,全面覆盖。可在执行test的时候指定一些参数,

  • -cover 可以查看覆盖率

  • -run regexp 只运行 regexp 匹配的函数,例如:-run Array 那么就执行包含有 Array 开头的函数,该参数支持通配符 *,和部分正则表达式,例如 ^$

  • -v 显示测试的详细信息 另外还有mock测试和基准测试,要实现每一次测试时都产生和之前一样的结果,不依赖于外部条件,则可以使用mock,在优化代码分析代码的时候则可以使用基准测试(testing.B)