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

91 阅读4分钟

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

1 语言进阶

1.1 并发和并行

并发(concurrency):把任务在不同的时间点交给处理器进行处理。在同一时间点,任务并不会同时运行。

并行(parallelism):把每一个任务分配给每一个处理器独立完成。在同一时间点,任务一定是同时运行。 并发不是并行。并行是让不同的代码片段同时在不同的物理处理器上执行。

GO可以充分发挥多核的优势,高效运行。

1.1.2 Gorutine

协程:用户态,轻量级的线程,栈kb级别,由go语言调用,go语言一次可以跑上万的协程。

线程:内核态,线程可以跑多个协程,栈mb级别

1.1.2.1协程的使用

非常简单,在函数前加go关键字就可以。

func f(){
    fmt.println("hello,world!")
}

func main(){
    go f()
}   

1.1.2.2协程的通信

两种方法,一种是通过通道实现通信,另一种是共享内存实现通信(必须使用互斥量,对内存进行加锁,保证数据访问的安全性,不同的gorutine之间会发生冲突)

Channel的创建
// make(chan 元素类型,[缓冲大小])
make (chan int,2) // 有缓冲通道

make (chan int) // 无缓冲通道 (todo:不知道这个的作用是啥,视频没有讲清楚)
  • 无缓冲的通道必须有一个接收的协程,否则发送方将一直阻塞。
  • channel 应仅由发送方执行,而不应由接收方执行,并且在收到最后发送的值后具有关闭通道的效果。
  • for循环可以遍历通道,直到通道关闭,理解的是,关闭后不再动态监听通道,而是遍历完当前通道内已有的元素。
共享内存区

必须对内存区的数据加锁,就是对于所有协程可以访问的数据结构要加锁

package main

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

var (
   x    int64
   lock sync.Mutex
)

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

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

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

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

加锁了可以加到10000,没有加锁的这个对临界区没有保护,结果无法追踪。

WaitGroup

主要目的是让主函数阻塞直到子协程执行完毕。

有一个写代码的方法,包装一个内部函数,在该内部函数里调用真正需要执行的函数和WaitGroup的Done方法,这样当功能函数执行完毕后,会调用WaitGroup的Done方法。

func hello(n int) {
   fmt.Printf("hello world %d\n", n)
}
func goWaitGroup() {
   var wg sync.WaitGroup
   wg.Add(4)
   for i := 0; i < 4; i++ {

      go func(j int) {
         defer wg.Done()
         hello(j)
      }(i)
   }
   wg.Wait()
}

2 依赖管理

2.1 最早的gopath

gopath下有三个目录,bin,pkg,src三个目录,项目的代码直接依赖src下的代码,go get下载的新版本的包也放到src目录下。

弊端

多个项目依赖于package的不同版本,无法实现package的多版本控制

2.2 Go Vendor

就是在项目的目录下增加一个vendor文件夹,所有依赖包副本形式都放在vendor下,依赖寻址的方式优先寻找vendor,找不到再去找gopath下, 这样就解决了多版本控制的问题。

弊端

他仍然是依赖的源代码,而不能标识依赖的版本

2.3 Go Module

通过go.mod文件管理依赖包版本

2.3.1 依赖管理的三要素:

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

2.3.2 go的设置

GOPROXY

代理配置,direct表示源站

GO111MODUL

GO111MODULE有三个值:off、on 和 auto(默认值)

GO111MODULE=off,无模块支持,go 会从 GOPATH 和 vendor 文件夹寻找包

GO111MODULE=on,模块支持,go 会忽略 GOPATH 和 vendor 文件夹,只根据 go.mod 下载依赖

GO111MODULE=auto,在 $GOPATH/src 外面且根目录有 go.mod 文件时,开启模块支持

2.3.3 go.mod详解

zhuanlan.zhihu.com/p/413040181

大版本号,表示兼容性,小版本号表示更新,最后的版本号表示bug修复。

2.4 依赖分发

最常见的是github

直接使用GitHub的依赖会有一些问题:

  1. 无法保证构建的稳定性,依赖软件会进行赠更改版本
  2. 无法保证依赖的可用性,可能删掉依赖
  3. 第三方平台的压力很大

为了解决上述问题,出现了一个proxy代理。这个proxy会更稳定,一般使用proxy进行依赖拉取。 (遇到设计的问题时,没有问题是proxy无法解决的,如果解决不了就建立两层proxy)

3 测试

todo

4 项目实战

todo