是我参与「第五届青训营 」伴学笔记创作活动的第 2 天
一、本堂课重点内容:
- 并发编程
- 依赖管理
- 单元测试
- 项目实战
二、详细知识点介绍:
并发编程
goroutine
Go 语言支持并发,我们只需要通过 go 关键字来开启 goroutine 即可。
goroutine 是轻量级线程,goroutine 的调度是由 Golang 运行时进行管理的,高效利用多核。(基于CPS并发模型)
goroutine 语法格式:
go 函数名( 参数列表 )
例如:
go f(x, y, z)
开启一个新的 goroutine:
f(x, y, z)
Go 允许使用 go 语句开启一个新的运行期线程, 即 goroutine,以一个不同的、新创建的 goroutine 来执行一个函数。 同一个程序中的所有 goroutine 共享同一个地址空间。
package main
import (
"fmt"
"time"
)
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s)
}
}
func main() {
go say("world")
say("hello")
}
注:函数的线程的执行顺序一定程度上依赖与函数定义和导入的顺序,导入>先定义>后定义,当主线程执行完成后,其余线程无论是否执行完成都会结束(可以通过通道阻塞线程来防止在其余线程执行结束前主线程结束)
package main
import (
"fmt"
"test/src/test"
"time"
)
func say2(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s, i+1, "say2")
}
}
func say(s string) {
for i := 0; i < 5; i++ {
time.Sleep(150 * time.Millisecond)
fmt.Println(s, i+1, "say")
}
}
func main() {
go say("world")
test.Say3("ok")
//say2("hello")
//go say2("world")
//say2("hello")
//ch := make(chan int)
//go say2("world", ch)
//say("hello")
//fmt.Println(<-ch)
}
package test
import (
"fmt"
"time"
)
func test() {
fmt.Println("hello world")
for i := 0; i > 1; i++ {
fmt.Println(i)
}
}
func Say3(s string) {
for i := 0; i < 5; i++ {
time.Sleep(100 * time.Millisecond)
fmt.Println(s, i+1, "say3")
}
}
chanel
通过通信共享内存(通道)而非通过共享内存而通信(临界区,加锁)
make(chan 元素类型,[缓冲大小])
//无缓冲通道(同步通道)
make(chan int)
//有缓冲通道(生产消费)
make(chan int, 2)
锁
Mutex
Mutex 是最简单的一种锁类型,同时也比较暴力,当一个 goroutine 获得了 Mutex 后,其他 goroutine 就只能乖乖等到这个 goroutine 释放该 Mutex。
RWMutex
RWMutex 相对友好些,是经典的单写多读模型。在读锁占用的情况下,会阻止写,但不阻止读,也就是多个 goroutine 可同时获取读锁(调用 RLock() 方法;而写锁(调用 Lock() 方法)会阻止任何其他 goroutine(无论读和写)进来,整个锁相当于由该 goroutine 独占。
依赖管理
不同模式的命令区别
1. gopath模式
在工程经过go build、go install或 go get等指令后,会将拉取的第三方xxx依赖包放在GOPATH/src目录下
2. go vendor模式
go build 时的应用路径搜索调整成为 优先搜当前工程路径/vendor目录
2. go module模式
- 拉取依赖路径
Go Modules 模式下,下载的包是存在 $GOPATH/pkg/mod 目录下的 - 拉取指定版本
GoModules 模式下,可以下载指定版本的包
单元测试
基础认识:
- 单元测试是比较底层的,关注代码的局部而不是整体。
- 单元测试是开发人员在写代码时候写的。
- 单元测试需要比其他测试模块先运行。
实例
func TestAbs(t *testing.T) {
got := Abs(-1)
if got != 1 {
t.Errorf("Abs(-1) = %d; want 1", got)
}
}
Mock
在写单测过程中,常会遇到有些不容易构造或者不容易获取的对象,这时候我们要创建一个虚拟的对象以便测试。
基准测试
项目实战
开发一个简易论坛后端