这是我参与「第三届青训营 -后端场」笔记创作活动的的第2篇笔记
theme: github highlight: a11y-dark
语言进阶
Goroutine
func c(i int) {
fmt.Println(i)
}
func main() {
for i := 0; i < 5; i++ {
go func(j int) {
c(j)
}(i)
}
//不能不sleep 否则main执行完就直接退出了 无法输出
time.Sleep(time.Second)
}
Channel
make(chan 元素类型,[缓冲大小]) 不给出缓冲大小:无缓冲通道 给出:有缓冲通道
使用:
func main() {
src := make(chan int)
dest := make(chan int, 3)
go func() {
defer close(src)
for i := 0; i < 10; i++ {
//这里是往src中放
src <- i
}
}()
go func() {
defer close(dest)
// i是从src中取出来的值
for i := range src {
//放入修改后的值
dest <- i * i
}
}()
// 进程2放入dest 主进程从dest中取
for i := range dest {
fmt.Println(i)
}
}
Lock
两种实现并发安全计数的方式
通过互斥锁锁住临界区
package main
import (
"fmt"
"sync"
"time"
)
var (
//全局x
x int64
//注意要定义lock
lock sync.Mutex
)
func addWithLock() {
for i := 0; i < 2000; i++ {
lock.Lock()
x += 1
lock.Unlock()
}
}
func main() {
for i := 0; i < 5; i++ {
go addWithLock()
}
//别忘了sleep 否则main执行完就退出
time.Sleep(time.Second)
fmt.Println(x)
}
WaitGroup
通过WaitGroup实例,Add申请计数器,Done对计数器-1,计数器为0时,Wait操作才会停止阻塞,放行。
package main
import (
"fmt"
"sync"
)
func main() {
//不加的话 main执行完就退出了
var wg sync.WaitGroup
wg.Add(5)
for i := 0; i < 5; i++ {
go func(j int) {
defer wg.Done()
fmt.Println(j)
}(i)
}
wg.Wait()
}
Go依赖管理
Go Module
三要素 go.mod
Proxy :GOPROXY
go get
go mod
测试
单元测试
-
文件命名:xxx_test.go
-
测试文件中方法命名:Test方法名(t *testing.T){}
-
执行测试时,测试前测试后的前置收尾工作放到TestMain方法中
-
执行测试:go test或者go test -v -v表示更详细
-
只有执行之后 在vscode才有方法左侧的三角执行按钮
func TestCalSquare(t *testing.T) {
CalSquare()
}
func TestMain(m *testing.M) {
fmt.Println("before test......")
//执行写的test方法
m.Run()
fmt.Println("after test......")
}
覆盖率
go test xxxx_test.go xxx.go -cover
单元测试覆盖率,使用--cover参数
Mock(模拟数据)
原本测试:从一个文件中读入
log文件:
line11
line22
line33
line44
line55
//方法
func ReadFirstLine() string {
open, err := os.Open("log")
defer open.Close()
if err != nil {
return ""
}
sanner := bufio.NewScanner(open)
for sanner.Scan() {
return sanner.Text()
}
return ""
}
//测试方法
func TestProcessFirstLineWithMock(t *testing.T) {
firstLine := ReadFirstLine()
assert.Equal(t, "line00", firstLine)
}
现在:
func TestProcessFirstLineWithMock(t *testing.T) {
//替换ReadFirstLine方法
//原本ReadFirstLine是从文件中读 现在是给一个函数返回
monkey.Patch(ReadFirstLine, func() string {
return "line110"
})
//还原
defer monkey.Unpatch(ReadFirstLine)
line := ProcessFirstLine()
assert.Equal(t, "line000", line)
}
基准测试
基准测试的目的是测试运行的性能
go test -bench=.
不要忘记最后面的点
执行结果:
func BenchmarkSelect(b *testing.B) {
InitServerIndex()
//resettime
b.ResetTimer()
for i := 0; i < b.N; i++ {
Select()
}
}
func BenchmarkSelectParallel(b *testing.B) {
InitServerIndex()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
Select()
}
})
}
func BenchmarkFastSelectParallel(b *testing.B) {
InitServerIndex()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
FastSelect()
}
})
}
goarch: amd64
pkg: github.com/Moonlight-Zhao/go-project-example/benchmark
cpu: Intel(R) Core(TM) i5-7360U CPU @ 2.30GHz
BenchmarkSelect-4 44696738 27.50 ns/op
BenchmarkSelectParallel-4 23511862 57.66 ns/op
BenchmarkFastSelectParallel-4 237921783 5.447 ns/op
PASS
ok github.com/Moonlight-Zhao/go-project-example/benchmark 6.468s