这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天。
语言进阶与依赖管理
1.协程 Goroutine
例:go func(j int){ fmt.Println(j) }(i)
2.通道 Channel
无缓冲通道 make(chan int)
有缓冲通道 make(chan int,2)
有缓冲通道发送数据的时候只有在缓冲区满的时候才会阻塞。同样的,接收数据的时候只有在缓冲区为空的时候才阻塞。
通过通信实现共享内存:
例:
src := make(chan int) //创建一个通道
src <- i //把i发送到channel src中
j := <- src //从src中接收数据赋给j
for i := range src // 遍历src中的数据
3.并发安全 Lock
当多个协程对同一个变量进行更改时,可能会出现并发安全问题。
var {
x int
lock sync.Hutex
}
lock.Lock()
x++ // 这里插入读写操作
lock.Unlock()
4.WaitGroup
用来实现并发任务的同步。
声明: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()
// 最后加上wg.Wait(),进行阻塞,保证子协程执行完之前主协程不退出。
5.go.mod
使用go mod init ProjectName生成go.mod文件,文件中第一行显示依赖管理的基本单元,为module + 自己init时写的ProjectName。接着是go原生库版本,最后是单元依赖。
6.Proxy 依赖分发
保证依赖分发的稳定性
7.go get/mod:
8.单元测试:
- 测试文件以_test.go结尾
- 方法名规则为TestXxx(*testint.T)
- 初始化逻辑放在TestMain中 单元测试例:
func HelloTom() string {
return "Tom"
}
func TestHelloTom(t *testing.T){
output := HelloTom()
expectOutput := "Tom"
if expectOutput != output {
t.errorf("Expected %s do not match actual %s",expectOutput,output)
}
}
- 单元测试-Mock 打桩测试,不在依赖本地文件 例 monkey : github.com/bouk/monkey…
monkey.Patch(target,replacement interface{}) //将target函数替换成replacement
monkey.Unpatch(target) //取消打桩
实战:
根据初始化话题数据索引写出初始化回帖数据索引:
func initPostIndexMap(filepath string) (error,map[int64]*Post) {
open,err := os.Open(filepath+"post")
if err != nil {
return err,nil
}
scanner := bufio.NewScanner(open)
PostsMap := make(map[int64]*Post)
for scanner.Scan() {
text := scanner.Text()
var post Post
if err := json.Unmarshal([]byte(text),&post); err != nil{
return err,nil
}
PostsMap[post.id] = &post
}
return nil,PostsMap
}
课后实践中存在的问题:
1.生成帖子时随机的id可能会和已有帖子的id重复
解决:在for循环例每生成一个随机id就查询PostsMap[id]是否存在,若不存在,则该id可用,退出循环。
2.Map并发性问题
解决:使用Lock或者使用sync.Map
sync.Map使用:
var scene sync.Map
// 将键值对保存到sync.Map
scene.Store("greece", 97)
scene.Store("london", 100)
scene.Store("egypt", 200)
// 从sync.Map中根据键取值
fmt.Println(scene.Load("london"))
// 根据键删除对应的键值对
scene.Delete("london")
// 遍历所有sync.Map中的键值对
scene.Range(func(k, v interface{}) bool {
fmt.Println("iterate:", k, v)
return true
})