Go 语言进阶与依赖管理 (二)day4| 青训营

121 阅读5分钟

今天是Go语言进阶与依赖管理其二。

1、Go并发编程

Sync

Go语言的sync包是Go标准库中提供的用于同步操作的包,它包含了一些常用的同步原语,如互斥锁、条件变量和等待组等,用于解决并发编程中的同步和数据竞争问题。
主要包括以下几点:

  1. 互斥锁(Mutex):sync.Mutex类型用于保护临界区,确保在同一时间只有一个协程可以访问共享资源。互斥锁提供了Lock和Unlock方法,分别用于获得锁和释放锁。我们在使用互斥锁时,需要谨慎避免死锁情况的发生。
  2. 等待组(WaitGroup):sync.WaitGroup类型用于等待一组协程的完成。等待组提供了Add、Done和Wait方法。Add用于增加等待的协程数量,Done用于标记一个协程的完成,Wait用于阻塞当前协程,直到所有协程都完成。 以下为lock的小例子
package main
import (
	"fmt"
	"sync"
)
type Counter struct {
	count int
	mu    sync.Mutex
}
func (c *Counter) Increment() {
	c.mu.Lock()         // 获取互斥锁
	defer c.mu.Unlock() // 在函数返回时释放互斥锁

	c.count++
}
func (c *Counter) Get() int {
	c.mu.Lock()
	defer c.mu.Unlock()

	return c.count
}
func main() {
	var wg sync.WaitGroup

	counter := Counter{}

	wg.Add(100)
	for i := 0; i < 100; i++ {
		go func() {
			counter.Increment()
			wg.Done()
		}()
	}
	wg.Wait()
	fmt.Println("Counter value:", counter.Get())
}

这段代码中定义了一个名为 Counter 的结构体,它包含一个整数类型的计数值和一个互斥锁 mu。Increment 方法用于将计数值加一,而 Get 方法用于返回计数值。在这两个方法中,使用 c.mu.Lock() 来获取互斥锁,在方法执行完后使用c.mu.Unlock() 释放互斥锁。在 main 函数中,创建了一个 Counter 实例 counter,并创建了 100 个协程来并发调用 counter.Increment() 方法来进行计数值的增加。使用 sync.WaitGroup 来等待所有协程完成。最后,通过调用 counter.Get() 方法来输出最终的计数值。通过使用互斥锁,确保了在同一时间只有一个协程可以修改计数值,实现了对临界区的互斥访问,保证了线程安全性。

WaitGroup

WaitGroup是Go语言标准库中 sync 包提供的一种并发原语,它用于等待一组协程的完成。 WaitGroup类型中有三个主要的方法:

  1. Add():将等待组的计数器加上 delta 值。当启动一个新的协程时,通常会调用 Add(1) 将计数器加一,表示有一个协程需要等待。
  2. Done():将等待组的计数器减一,相当于 Add(-1)。在协程执行完任务后,应调用该方法来标志协程的完成。
  3. Wait():阻塞当前协程,直到等待组的计数器归零。当所有的协程都执行完任务,并且调用了 Done() 方法后,Wait() 方法会解除阻塞,继续往下执行。

WaitGroup 提供了一种方便的方式来等待一组协程的完成,特别适合在主协程中等待并发任务的完成。通过 WaitGroup 可以避免使用临时变量、通道等手动同步的麻烦,使得并发编程更加简洁和优雅。同时,还可以保证主协程在所有任务完成后再继续执行,从而保证结果的正确性。在使用 WaitGroup 时,需要确保在协程中调用 Done 方法,否则可能会导致 Wait 方法永久阻塞。另外,Add 方法的参数可以是正数、零或负数,但需要保证最终计数器的值为零才能解除阻塞。

2、go的依赖管理:GOPATH,Go Vender和Go Module

Go的依赖管理经历了三个阶段:GOPATH、Go Vendor和Go Module。

  1. GOPATH:
    GOPATH 是 Go 语言中用于保存源码和依赖包的工作空间。 默认情况下,GOPATH 指向一个目录,其中包含三个子目录:src、pkg 和 bin。 src 目录用于存放源代码,pkg 目录用于存放编译后的包(二进制文件),bin 目录用于存放可执行文件。 通过使用 go get 命令可以获取依赖包并将其放入 GOPATH 中的相应位置。 GOPATH 是 Go 语言早期应用最广泛的依赖管理方式,适用于单个项目或小规模项目。
  2. Go Vendor:
    Go Vendor 是 Go 1.5 版本之后引入的一种官方依赖管理方式。 在项目根目录下创建 vendor 目录,并将依赖包的源码复制到该目录中。 在构建项目时,Go 编译器首先会从 vendor 目录中查找依赖包,如果找不到才会去 GOPATH 或 GOROOT 下查找。 可以使用 go mod vendor 将依赖包直接复制到 vendor 目录中,方便项目的分发和构建。 Go Vendor 适用于需要精确控制依赖版本,以确保在不同环境下的一致性。
  3. Go Module: Go Module 是 Go 1.11 版本之后引入的官方依赖管理方式,也是目前推荐的方式。 使用 Go Module 可以在每个项目中独立管理其依赖关系,不再需要依赖全局 GOPATH 的设置。 在项目根目录中运行 go mod init 命令,Go 会根据导入的包自动创建 go.mod 文件来记录依赖关系。 通过运行 go get 命令可以获取和更新依赖包,并将其记录在 go.mod 文件中。 Go Module 还支持语义化版本控制 (Semantic Versioning),可以更方便地管理依赖版本。 使用 Go Module 可以方便地与其他开发者共享项目,确保他们获得相同的依赖项。

3、总结

Go 语言的依赖管理是一个不断演进的过程。在发展的过程中,从最初的 GOPATH 方式,到后来的 Go Vendor,再到现在推荐的 Go Module,每一种方式都有其独特的优势和适用场景。正如我们的学习,可能不会一帆风顺,会遇到许多困难,我们也应该不断演进和发展,找到适合自己的道路。