这是我参与「第三届青训营 -后端场」笔记创作活动的的第2篇笔记
go内容简图:
1.语言进阶
1.1并发与并行
简单理解图:
go语言可以充分发挥多核优势,高效运行
协程与线程
协程:用户态,轻量级线程,栈MB级别
线程:内核态,线程跑多个协程,栈KB级别
快速打印 hello goroutine 代码实现:
package main
import (
"fmt"
"time"
)
func hello(i int) {
fmt.Println("hello goroutine : " + fmt.Sprint(i))
}
func hellogoroutine() {
for i := 0; i < 5; i++ {
go func(j int) {
hello(j)
}(i)
//go hello(i)
}
time.Sleep(time.Second)
}
func main() {
hellogoroutine()
}
代码实现截图:
1.2 CSP
提倡通过通信共享内存而不是通过共享内存实现通信
1.3 Channel
用法:
make(chan 类型,缓冲大小)
- 无缓冲通道 make(chan char)
- 有缓冲通道 make(chan char,2)
示例代码:
import "fmt"
func main() {
CalSquare()
}
func CalSquare() {
src := make(chan int)
dest := make(chan int, 3)
go func() {
defer close(src)
for i := 0; i < 10; i++ {
src <- i
}
}()
go func() {
defer close(dest)
for i := range src {
dest <- i * i
}
}()
for i := range dest {
fmt.Println(i)
}
}
运行结果截图:
运行结果分析:
在A协程处我们输入从0到9的数字
在B协程处,我们将计算A协程我们输入的数字的平方
在主程处,我们输出最后的结果
1.4 并发安全Lock
示例代码:
import (
"fmt"
"sync"
"time"
)
func main() {
x = 0
for i := 0; i < 10; i++ {
go addwithoutlock()
}
time.Sleep(time.Second)
fmt.Println("withoutlock ans:" + fmt.Sprint(x))
x = 0
for i := 0; i < 10; i++ {
go addwithlock()
}
time.Sleep(time.Second)
fmt.Println("withlock ans:" + fmt.Sprint(x))
}
var (
x int64
lock sync.Mutex
)
func addwithlock() {
for i := 0; i < 200; i++ {
lock.Lock()
x += 1
lock.Unlock()
}
}
func addwithoutlock() {
for i := 0; i < 200; i++ {
x += 1
}
}
结果截图:
此时我们可以看到 在数据量比较小的情况下 加锁和不加锁的结果是一样的
但是我们把数据量增加100倍之后
我们可以看到,加锁的结果是正确的,而不加锁的结果会明显的小了很多,造成了数据的缺失。
1.5 WaitGroup
计数器开启协程+1
执行结束-1
主协程阻塞知道计数器为0
代码部分:
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
wg.Add(5)
for i := 0; i < 5; i++ {
go func(j int) {
defer wg.Done()
hello(j)
}(i)
}
wg.Wait()
}
func hello(i int) {
fmt.Println(i)
}
运行结果:
代码分析:
首先创建一个WaitGroup wg
在wg里面增加5个协程
然后运行5个协程,每个协程运行结束时wg阻塞器中的值减一,当阻塞器中的值为0时,主程序运行,结束程序
2.依赖管理
- 工程项目不可能基于标准库的0~1代码搭建
- 管理依赖库
2.1 go的依赖管理
- 不同环境(项目)依赖的版本不同
- 控制依赖库的版本
- 项目代码直接依赖src下的代码
- go get 下载最新版本的包到src目录下
go mod 指令
2.2 依赖管理三要素
- 配置文件,描述依赖 go.mod
- 中心仓库管理依赖库 Proxy
- 本地工具 go get/mod
3.测试
3.1 测试规则
- 所有测试文件以 _test.go 结尾
- func TestXxx(*testing.T)
- 初始化逻辑放到TestMain中
示例代码:
/*
**hellotom_test.go
*/
package main
import (
"testing"
"github.com/stretchr/testify/assert"
)
func testhellotom(t *testing.T) {
output := hellotom()
ans := "Tom"
assert.Equal(t, ans, output)
if output != ans {
t.Errorf("Expect %s do not match actual %s", ans, output)
}
}
/*
**hellotom.go
*/
package main
func hellotom() string {
return "Jerry"
}
截图:
3.2 覆盖率
- 如何衡量代码是否经过了足够的测试
- 如何评价项目的测试水准
- 如何评估项目是否达到了高水准测试等级
因此go语言给出了一种测试方法,测试代码覆盖率
/*
**代码覆盖率.go
*/
package main
func judgepassline(score int16) bool {
if score > 60 {
return true
}
return false
}
/*
**代码覆盖率_test.go
*/
package main
import (
"testing"
"github.com/stretchr/testify/assert"
)
func testjudgepasslinetrue(t *testing.T) {
ispass := judgepassline(70)
assert.Equal(t, true, ispass)
}
func testjudgepasslinefalse(t *testing.T) {
ispass := judgepassline(50)
assert.Equal(t, false, ispass)
}
4.项目实践
因本人能力有限,实现不出来该项目。(萌新求放过)