go项目依赖

109 阅读1分钟

go语言入门:工程实践

1.go的优势:

1.go可以发挥多核优势,高效运行高并发

协程(goroutine) :用户级,轻量级线程,栈KB级别

线程:系统级,轻量级线程,栈MB级别

线程上可以跑多个协程,go语言可以一次跑上万个协程。

一个协程小demo

package main
//快速打印
import (
    "fmt"
    "time"
)
​
func hello(i int) {
    fmt.Println("hello goroutine:", i)
}
func HelloGoroutine() {
    for i := 0; i < 5; i++ {
        //调用协程的格式
        go func(i int) {
            hello(i)
        }(i)
    }
    //等待防止主协程退出
    time.Sleep(time.Second)
}
​
func main() {
    HelloGoroutine()
}
/*打印结果:
hello goroutine: 0
hello goroutine: 1
hello goroutine: 4
hello goroutine: 2
hello goroutine: 3
*/
每次都是不一样的乱序说明打印操作是并发的
​

进程信息交换

Channel:

建立语法:

make(chan elemtype,[bufSize])
//注:方括号[]表示可选
无缓冲通道:make(chan int)   通信是完全同步的
有缓冲通道:make(chan int,2) 

channel

channel demo:

package main
​
import "time"func printSquare() {
    src := make(chan int)
    dest := make(chan int, 3)
    //用于生产数字
    go func() {
        defer close(src)
        for i := 0; i < 10; i++ {
            src <- i
        }
    }()
​
    //用于接收并计算平方,再输入到另一个带有缓冲区的通道dest中
    go func() {
        defer close(dest)
        for i := range src {
            dest <- i * i
        }
​
    }()
    for i := range dest {
        println(i)
​
    }
}
​
func main() {
    printSquare()
}
​

一个关键的知识点:弄清缓冲与缓存

详见:性能优化--面试官问缓冲与缓存有什么区别? - 知乎 (zhihu.com)

这里总结一下我的理解:

*缓冲(buffer) *在两个端进行数据交换时,如果A产出物品B再拿走,那么当B没有拿走物品的时候A也无法产出。设置缓冲区的目的就是类似于包饺子时候放饺子皮的盆。让制作饺子皮和拿取饺子皮的人都可以按自己原来的节奏持续放/拿取。

*缓存(cache) *是针对局部性设计的为了将可能用到的已经调用过的数据来放到更高速的空间上来加快效率。

Sync关键字来控制线程/协程安全

并发安全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()
}
​

Lock输出

不上锁时协程可能抢占导致数据更改出问题(并发安全问题)

WaitGroup(信号量):

waitgroup

Demo:利用waitgroup来优化代码

原始代码

原始代码

优化后

优化后

2.依赖管理:

Go依赖管理演进路线

GOPATH->GO Vender->GO Module

Gopath:

项目直接依赖于src里的源代码。存在的问题:在package更新迭代后可能不适配。

Gopath

GoVender:

在每个项目下面都增加有vendor文件夹,每个项目依赖的副本都放到这个文件夹下,在进行项目依赖的时候先到govender文件夹下找,如果找不到的话再去gopath。

gowender

Gomodule:

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

image-20230523223341440

项目依赖:

image-20230523223930350

代码溯源:

如果直接从github这种的代码仓库去找不同版本的依赖的话可能存在着各种各样的问题,如果源代码进行修改,删除的话就寄了。而为了解决这个问题我们用来中间件proxy。

Goproxy

依赖的分发:

image-20230523224440421

工具:

go get:

image-20230523224945905

go mod:

image-20230523225004659

Go Module实践