Go语言进阶、依赖与测试|青训营笔记

84 阅读3分钟

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

前言

  • 并发编程
  • 依赖管理
  • 测试

一、并发编程

参考教程:Go 并发 | 菜鸟教程 (runoob.com)

1. goroutine

Go语言支持并发,只需要使用Go关键字启动即可。

package main
import(
	"fmt"
	"time"
)
func say(s string){
	for i:=0;i<2;i++{
		time.Sleep(100*time.Millisecond)
		fmt.Println(s)
	}
}
func main(){
	go say("1")
	say("2")
}

则对应输出为

2
1
1
2

2.通道(channel)

  • 通道(channel)是用来传递数据的一个数据结构。
  • 通道可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯。
  • 操作符 <- 用于指定通道的方向,发送或接收。如果未指定方向,则为双向通道。
package main
import(
	"fmt"
)

func sum(s []int,ch chan int){
	sum:=0
	for _,v:= range s{
		sum+=v
	}
	ch<-sum //把sum输出到通道ch
}

func main(){
	s:=[]int{7,2,8,-9,4,0}
	ch:=make(chan int)
	go sum(s[:len(s)/2],ch)
	go sum(s[len(s)/2:],ch)
	x,y := <-ch, <-ch //从通道ch中接收
	fmt.Println(x,y,x+y)
}

则相应输出为:

 -5 17 12

注意:这里使用的channel是无缓冲区的。 下面介绍带缓存的通道

package main
import "fmt"
func main(){
	//这里我们定义了一个可以存储整数类型的带缓冲通道
	//缓冲区大小为2
	ch:=make(chan int,2)

	//因为ch是带缓冲的通道,我们可以同时发送两个数据
	//而不用立刻需要去同步读取数据
	ch<-1
	ch<-2
	//获取两个数据
	fmt.Println(<-ch)
	fmt.Println(<-ch)
}

则对应的输出为:

1
2

3. 互斥锁

Go语言包中的 sync 包提供了两种锁类型:sync.Mutex 和 sync.RWMutex。
Mutex:互斥锁。
RWMutex:单写多读模型。

package main
import (
    "fmt"
    "sync"
)
var (
    // 逻辑中使用的某个变量
    count int
    // 与变量对应的使用互斥锁
    countGuard sync.Mutex
)
func GetCount() int {
    // 锁定
    countGuard.Lock()
    // 在函数退出时解除锁定
    defer countGuard.Unlock()
    return count
}
func SetCount(c int) {
    countGuard.Lock()
    count = c
    countGuard.Unlock()
}
func main() {
    // 可以进行并发安全的设置
    SetCount(1)
    // 可以进行并发安全的获取
    fmt.Println(GetCount())
}

则对应输出为:

1

4.WaitGroup

  • 在 sync.WaitGroup(等待组)类型中,每个 sync.WaitGroup 值在内部维护着一个计数,此计数的初始默认值为零。
  • 等待组内部拥有一个计数器,计数器的值可以通过方法调用实现计数器的增加和减少。
  • 当我们添加了 N 个并发任务进行工作时,就将等待组的计数器值增加 N。
  • 每个任务完成时,这个值减 1。同时,在另外一个 goroutine 中等待这个等待组的计数器值为 0 时,表示所有任务已经完成。
package main

import (
	"fmt"
	"net/http"
	"sync"
)
func main() {
	var wg sync.WaitGroup					// 声明一个等待组
	var urls = []string{					
		"https://www.baidu.com/",
		"https://www.163.com/",
		"https://www.weibo.com/",
	}
	for _, url := range urls {
		wg.Add(1)						// 每个任务开始,等待组+1
		go func(url string) {
			defer wg.Done()
			_, err := http.Get(url)		// 执行访问
			fmt.Println(url, err)
		}(url)
	}
	wg.Wait()						// 等待所有任务完成
	fmt.Println("over")
}

二、依赖管理

参考:Go语言go mod包依赖管理工具使用详解 (biancheng.net)
go module 是Go语言从 1.11 版本之后官方推出的版本管理工具,并且从 Go1.13 版本开始,go module 成为了Go语言默认的依赖管理工具。

三、测试

参考:go test命令(Go语言测试命令)完全攻略 (biancheng.net)
Go语言拥有一套单元测试和性能测试系统,仅需要添加很少的代码就可以快速测试一段需求代码。
go test 命令,会自动读取源码目录下面名为 *_test.go 的文件,生成并运行测试用的可执行文件。