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

59 阅读3分钟

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

语言进阶

介绍

并发:多线程程序在一个核的cpu上运行

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

Go可以充分发挥多核优势,高效运行

Go语言一次可以创建上万个协程

Goruotine是协程

只需要在一个函数前面加上 go 关键词,就可以让这个函数以一个协程来运行

package main
​
import (
    "fmt"
    "time"
)
​
func printhello(i int) {
    fmt.Println("hello goroutine:", i)
}
​
func main() {
    for i := 0; i < 5; i++ {
        go func(j int) {
            printhello(j)
        }(i) //这个i传递给上面的j
    }
    time.Sleep(time.Second) //time.Second是1秒,这个设置来是保证子协程在执行完之前主线程不至于退出
}

提倡通过通信共享内存而不是共享内存而实现通信

通过通信共享内存:Gorountine1通过通道传输值给另一个Gorountine2

通过共享内存实现通信:要有互斥量,对临界区加锁。

channel

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

  • 无缓冲通道 make(chan int),发送的gorountine和接受的gorountine同步化,又称同步通道
  • 有缓冲通道 make(chan int, 2),2代表缓冲区的容量

有缓冲是因为消费者与生产者速度不同。这样不会因为消费者速度过低而影响生产者高速生产。

A 子协程发送0~9数字

B 子协程计算输入数字的平方

主协程输出最后的平方数

package main
​
import "fmt"func main() {
    src := make(chan int)
    dest := make(chan int, 3)//有缓冲是因为消费者与生产者速度不同。(下面有输出)
    //A
    go func() {
        defer close(src)
        for i := 0; i < 10; i++ {
            src <- i
        }
    }()
    //B
    go func() {
        defer close(dest)
        for i := range src {
            dest <- i * i
        }
    }()
    //主
    for i := range dest {
        fmt.Println(i)
    }
}

并发安全 Lock

记得要time.Sleep(time.Second),等子协程做完,不然会出错。

有了锁,这样就不会变量冲突。

package mainimport (
    "fmt"
    "sync"
    "time"
)
​
var x int
var lock sync.Mutexfunc addWithLock() {
    for i := 0; i < 2000; i++ {
        lock.Lock()
        x++
        lock.Unlock()
    }
}
​
func addWithoutLock() {
    for i := 0; i < 2000; i++ {
        x++
    }
}
​
func main() {
    x = 0
    for i := 0; i < 5; i++ {
        go addWithLock()
    }
    time.Sleep(time.Second)
    fmt.Println("WithLock x:", x)
​
    x = 0
    for i := 0; i < 5; i++ {
        go addWithoutLock()
    }
    time.Sleep(time.Second)
    fmt.Println("WithoutLock x:", x)
}
/*
WithLock x: 10000
WithoutLock x: 8116
*/

WaitGroup

另一种方法

func main() {
    var wg sync.WaitGroup
    wg.Add(5)
    for i := 0; i < 5; i++ {
        go func(j int) {
            defer wg.Done()
            printhello(j)
        }(i)
    }
    wg.Wait()//主协程阻塞直到计数器为0
}

依赖管理

Go Module

  • 通过go.mod文件管理依赖包版本
  • 通过go get/go mod指令工具管理依赖包

终极目标:定义版本规则和管理项目依赖关系

依赖管理三要素

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

go.mod文件,间接依赖会用//indirect标识

版本比较老的就没有go.mod文件

不能直接用github这样代码托管平台作为依赖,有可能被修改删除;负载大

工具 - go get

go get example.org/pkg

  1. @update 默认
  2. @none 删除依赖
  3. @v1.1.2 tag版本,语义版本
  4. @23dfdd5 特定的commit提交
  5. @master 分支的最新commit

工具 - go mod

go mod

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