Go高并发编程以及依赖管理

129 阅读2分钟

携程

协程与线程的区别:

协程:运行在用户态,而且相比较于线程开销更小。

线程:线程属于内核态资源,由多个线程组成。

通过go来开启一个协程

package main

import (
   "fmt"
   "time"
)

func hello(j int) {
   fmt.Println("hello:", j)
}

func main() {
   for i := 0; i <= 4; i++ {
      go hello(i)
   }
   time.Sleep(time.Second)
}

协程通信

协程通信可以有两种方式:

  1. 通过通信来实现共享内存(主要)

  2. 通过共享内存来实现通信。

创建channel

使用make(chan 元素类型,缓冲区大小) 来创建,没有缓冲区大小字段则为无缓冲(同步)通道

比如make (chan int, 2)来创建一个缓冲区大小为2的管道,make(chan int)来创建一个无缓冲通道。

示例代码:

package main

import (
   "fmt"
)

func hello(j int) {
   fmt.Println("hello:", j)
}

func main() {
   src := make(chan int)
   dest := make(chan int, 3)

   go func() {
      defer close(src)
      for i := 0; i < 10; i++ {
         src <- i
      }
   }()

   go func() {
      defer close(dest)
      for i := range src {
         dest <- i * i
      }
   }()

   for i := range dest {
      fmt.Println(i)
   }
}

锁机制:

package main

import (
   "fmt"
   "sync"
   "time"
)

var x int64
var lock = sync.Mutex{} //获取一把锁

func addWithoutLock() {
   for i := 1; i <= 2000; i++ {
      x++
   }
}

func addWithLock() {
   for i := 1; i <= 2000; i++ {
      lock.Lock()
      x++
      lock.Unlock()
   }
}

func main() {
   x = 0
   for i := 1; i <= 5; i++ {
      go addWithoutLock()
   }
   time.Sleep(time.Second)
   println(x)
   x = 0
   for i := 1; i <= 5; i++ {
      go addWithLock()
   }
   time.Sleep(time.Second)
   fmt.Println(x)
}

WaitGroup

开启一个协程+1,结束一个协程-1,主协程阻塞直到计数器为0。

package main

import (
   "fmt"
   "sync"
)

func hello(j int) {
   fmt.Println("hello:", j)
}

func main() {
   var wg = sync.WaitGroup{}
   wg.Add(5) //有五个协程所以直接+5
   for i := 0; i <= 4; i++ {
      go func(j int) {
         defer wg.Done()//标记协程已经完成
         hello(j)
      }(i)
   }
       wg.Wait() //等待计数器为0
}

依赖管理

管理方式

GOPATH

主要使用文件结构

  • pkg
  • bin
  • src

缺点:没有多版本依赖控制

Go Vendor

在Vendor中保存一个项目依赖的副本

缺点:

  • 无法控制依赖版本
  • 可能存在依赖冲突,导致编译出错的问题

Go mod(目前)

通过go.mod文件管理以来包版本

通过go get / go mod置顶工具管理依赖

管理三要素

1.配置文件,描述依赖

2.中央仓库代理

3.本地工具

依赖配置Version

语义化版本:${MAJOR}.${MINOR}.${PATCH}如V1.3.0,V2.3.0

基于Commit的伪版本vx.0.0-yyyymmddhhmmss-abcdefg1234

测试

单元测试

测试方法:通过编写xxx_test.go文件(标准)来进行测试

评估标准:代码覆盖率(具体执行了多少行的代码)

一般覆盖率:50~60%

较高覆盖率:80%以上

Mock测试

测试文件存在本地依赖的情况(如文件等),此时可以使用Mock测试来替换相对应的函数,摆脱本地环境的依赖。

基准测试

  • 优化代码
  • 测试代码运行速度