Go 语言进阶与依赖管理 | 字节青训营

105 阅读2分钟

并发VS并行

  • 并发指多线程程序在一个核的cpu上运行
  • 并行指多线程程序在多个核的cpu上运行 Go语言可以充分发挥多核优势,高效并行

Goroutine

image.png 协程:用户态,轻量级线程,栈kb级别 线程:内核态,线程跑多个协程,栈mb级别

快速打印hello goroutine

package main

import (
   "fmt"
   "time"
)

func hello(i int) {
   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)
}
func main() {
   HelloGoroutine()
}
/*
hello goroutine :0
hello goroutine :4
hello goroutine :3
hello goroutine :2
hello goroutine :1
*/

CSP(Communicating Sequential processes)

提倡通过通信共享内存而不是共享内存实现通信,也就是提倡使用管道 image.png

Channel

make(chan 元素类型,[缓冲大小])

  • 无缓冲通道 make(chan int)
  • 有缓冲通道 make(chan int ,2) 带缓存的Channel可以解决由于生产,消费者速度不同带来的问题 image.png
package channel

func CalSquare() {
   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)
   }
}
/*0
1
4
9
16
25
36
49
64
81
*/

并发安全 Lock

package main

import (
   "sync"
   "time"
)

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

}
func main() {
   Add()
}
/*
WithoutLock: 8898
WithLock: 10000
*/ 

WaitGroup

package main

import "sync"

func hello(i int) {
   println(i)
}
func ManyGowWait() {
   var wg sync.WaitGroup
   wg.Add(5)
   for i := 0; i < 5; i++ {
      go func(j int) {
         defer wg.Done()
         hello(j)
      }(i)
   }
   wg.Wait()
}
func main() {
   ManyGowWait()
}
/*
0
2
3
4
1
*/

依赖管理

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

Go 依赖管理演进

GOPATH->GO Vendor->Go Module

  • 不同环境(项目)依赖的版本不同

GoPATH

GOPATH路径应有bin,pkg,src文件夹

  • bin保存项目编译的二进制文件
  • pkg保存项目编译的中间产物,加速编译
  • src保存项目源码

GoPATH-弊端

假如项目A和B依赖于某一个package的不同版本,package无法实现多版本控制

Go Vendor

  • 项目目录下增加vendor文件,所有依赖包的副本形式放在$ProjectRoot/vendor
  • 依赖寻址方式:vendor ->GOPATH

Go Vendor-弊端

一旦版本更新可能导致不兼容

Go Module

  • 通过go.mod文件管理依赖包版本
  • 通过go get/go mod 指令工具管理依赖包
  • 定义版本规则和项目的依赖关系

依赖管理三要素

  • 配置文件,描述依赖 go.mod
  • 中心仓库管理依赖库 Proxy
  • 本地工具 go get/mod

依赖配置- go.mod

module test//依赖管理单元

go 1.19   //原生库

require (//单元依赖
   github.com/gin-contrib/sse v0.1.0 // indirect
   github.com/gin-gonic/gin v1.8.2 // indirect
   github.com/go-oauth2/oauth2/v4 v4.5.2 // indirect
   github.com/go-playground/locales v0.14.0 // indirect
   github.com/go-playground/universal-translator v0.18.0 // indirect
   github.com/go-playground/validator/v10 v10.11.1 // indirect
   github.com/go-session/session v3.1.2+incompatible // indirect
   github.com/go-sql-driver/mysql v1.7.0 // indirect
   github.com/goccy/go-json v0.9.11 // indirect
   github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
   github.com/golang/protobuf v1.5.3 // indirect)

依赖配置-version

语义化版本

  • MAJOR.{MAJOR}.{MINOR}.${PATCH} 基于commit伪版本 vx.0.0-yyyymmddhhmmss-abcdefgh1234 第一部分类似版本好,第二部分为提交时间,第三为哈希码前12位

依赖配置-indirect

module test//依赖管理单元

go 1.19   //原生库

require (//单元依赖
   github.com/gin-contrib/sse v0.1.0 // indirect    <-此为间接引用
   github.com/gin-gonic/gin v1.8.2 // indirect
   github.com/go-oauth2/oauth2/v4 v4.5.2 // indirect
   github.com/go-playground/locales v0.14.0 // indirect
   github.com/go-playground/universal-translator v0.18.0 // indirect
   github.com/go-playground/validator/v10 v10.11.1 // indirect
   github.com/go-session/session v3.1.2+incompatible // indirect
   github.com/go-sql-driver/mysql v1.7.0 // indirect
   github.com/goccy/go-json v0.9.11 // indirect
   github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
   github.com/golang/protobuf v1.5.3 // indirect)

image.png

依赖配置-incompatible

module test//依赖管理单元

go 1.19   //原生库

require (//单元依赖
   github.com/gin-contrib/sse v0.1.0 // indirect    <-此为间接引用
   github.com/gin-gonic/gin v1.8.2 // indirect
   github.com/go-oauth2/oauth2/v4 v4.5.2 // indirect
   github.com/go-playground/locales v0.14.0 // indirect
   github.com/go-playground/universal-translator v0.18.0 // indirect
   github.com/go-playground/validator/v10 v10.11.1 // indirect
   github.com/go-session/session v3.1.2+incompatible // indirect
   github.com/go-sql-driver/mysql v1.7.0 // indirect
   github.com/goccy/go-json v0.9.11 // indirect
   github.com/golang-jwt/jwt v3.2.2+incompatible    <-主版本2+模块会在模块路径增加/vN后缀  // indirect
   github.com/golang/protobuf v1.5.3 // indirect)

依赖配置 兼容

在编译时会使用最低兼容度的版本

依赖分发-回源

如果使用第三方仓库会导致很多问题,比如:原作者修改,删除代码,平台压力过大删除

依赖分发-Proxy

proxy会缓存网站内容,使其稳定可靠

依赖分发- 变量 GOPROXY

当需要依赖时,先从PROXY1获取,再从PROXY2获取,直到全部获取并且都失败,从源站点获取

工具- go get

go get example.org/pkg

  • @update 默认
  • @none 删除依赖
  • @v1.1.2 tag版本,语义版本
  • @23dfdd5 特定的commit
  • @master 分支的最新commit

工具- go mod

go mod

  • init 初始化,创建go.mod文件
  • download 下载模块到本地缓存
  • tidy 增加需要的依赖,删除不需要的依赖

小结

主要学习了GO的协程与线程和依赖管理工具的使用