Go语言进阶与依赖管理 | 青训营笔记

59 阅读1分钟

这是我参与「第五届青训营 」笔记创作活动的第2天

1.本堂课重点内容

  • 从并发编程了解Go高性能的本质
  • 了解go语言的依赖管理

2.具体案例

  1. 协程的使用,快速打印hello goroutine
  2. Channel的具体使用

3.Go高性能的本质

3.1 并发

多线程程序在一个核的cpu上运行 通过时间片的切换,实现同时运行的状态

3.2 并行

多线程程序在多个核的cpu上运行

3.3 Goroutine

3.3.1 线程与协程

线程是系统比较昂贵的系统资源,操作是系统操作。
协程是轻量级的线程,操作是程序员操作

  • 协程:用户态,轻量级线程,栈KB级别
  • 线程:内核态,线程可以跑多个协程,栈MB级别
3.3.2 协程的使用

go语言调用协程非常简单,只需要在要调用的方法前加go关键字
注意:如果不加阻塞,子协程在执行完成前,主线程可能已经退出,导致运行框无结果。

func name(){
    语句
}
func main(){
    go func(){
        name()
    }()
    阻塞
}

课程实例

func hello(i int)  {
   fmt.Println("hello goroutine : " + fmt.Sprint(i))
}

func HelloGoRoutine()  {
   for i := 0; i < 5; i++ {
      go func(j int) {  // 使用协程
         hello(j)
      }(i) //传入的参数
   }
   time.Sleep(time.Second)   //阻塞
}

3.4 协程间的通信(CSP)

3.4.1 通信共享内存与共享内存实现通信

提倡通过通信共享内存,而不是通过共享内存实现通信 image.png 主要使用通道channel 遵循先入先出
通过一个协程发送信息到其他协程

image.png 影响程序的性能

3.4.2 Channel

Channel类型的定义

//无缓冲通道
make(chan 元素类型)
//有缓冲通道
make(chan 元素类型, [缓冲大小])

有缓冲与无缓冲的区别

  • 无缓冲会使接收的goroutine与发送的goroutine同步化简称同步通道
  • 有缓冲通道解决同步问题

Channel的具体使用

//无缓冲
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 {
   println(i)
}

3.5 并发安全Lock

使用锁机制保证并发安全

lock.Lock()  加锁
lock.Unlock() 释放

eg:

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("WithLock:", x)
   x = 0
   for i := 0; i < 5; i++ {
      go addWithoutLock()
   }
   time.Sleep(time.Second)
   println("WithoutLock:", x)
}

image.png

3.6 WaitGroup

等于是一个计数器,每开启一个协程就加一,协程执行完毕后减一,可以使用Wait方法阻塞直到所有的协程停止

var wg sync.WaitGroup  //WaitGroup声名
wg.Add(协程数量)
wg.Done()    //协程关闭后减一
wg.Wait()   //阻塞直到所有的协程关闭

4. go语言的依赖管理

4.1 背景

  • 工程项目不可能基于标准库0~1编码搭建
  • 管理依赖库

4.2 依赖管理演进

  • GOPATH
    环境变量 $GOPATH
    项目代码直接依赖src下的代码
    go get 下载到src下
    弊端
    无法实现package的多版本控制
  • Go Vendor
    依赖寻址方式:vendor => GOPATH
    弊端
    依赖冲突
  • Go Module
    通过go.mod文件管理依赖包版本
    通过go get/mod 指令管理依赖包

4.3 依赖管理三要素

  1. 配置文件,描述依赖
  2. 中心仓库管理依赖库
  3. 本地工具