Go语言进阶 | 青训营笔记

218 阅读3分钟

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

Go语言进阶

一、Go并发编程

1、线程与协程

  • 线程属于内核态由操作系统调度 开启及关闭线程都是重型操作
  • 协程属于用户态由Go语言开启 一个线程可以同时运行多个协程
  • Go语言可同时开启几万个协程(Go语言适合高并发的原因)

2、并发与并行

  • 并发:多线程程序在单核CPU上运行(通过时间片控制)
  • 并行:多线程程序在多核CPU上运行

3、Go语言开启协程

在函数前加go即可开启协程

    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")  
    }

4、协程通信的两种方式

  • 通过通信共享内存(Go语言中的主要方式)
  • 通过共享内存实现通信(Go语言仍然保存 通过加互斥锁实现 会影响效率)

5、Channel

通道(channel)是用来传递数据的一个数据结构。

通道可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯。操作符 <- 用于指定通道的方向,发送或接收。如果未指定方向,则为双向通道。 带缓冲的channel可以解聚生产者消费者处理速率不均衡带来的效率问题

package main

import (
   "sync"
   "time"
)

var (
   x    int64
   lock sync.Mutex
)

func addWithLock() {
   for i := 0; i < 2000; i++ {
      lock.Lock()
      x += 1
      lock.Unlock()
   }
}
func addWithoutLock() {
   for i := 0; i < 2000; i++ {
      x += 1
   }
}
func main() {
   x = 0
   for i := 0; i < 5; i++ {
      go addWithLock()
   }
   time.Sleep(time.Second)

   println("add withlock:", x)

   x = 0
   for i := 0; i < 5; i++ {
      go addWithoutLock()
   }
   time.Sleep(time.Second)

   println("add withoutlock:", x)
}

二、Go依赖管理

Gopath

缺点:不同模块依赖同一个包但依赖版本不同时会出现版本问题

GoVendor

缺点:同一个项目依赖不同包时 会有代码冲突问题

GoModule

解决了Gopath与GoVendor的问题 定义了版本规则与管理项目依赖关系

依赖管理三要素

image.png

Proxy

Proxy会将代码托管平台的依赖进行缓存,实现了可靠稳定的依赖管理,避免了对第三方代码托管平台的大流量访问 image.png

GoProxy环境变量设置

资源查找顺序 先到Proxy1 再到 Proxy2 都找不到后回到源站找 image.png

Goget

可以拉取不同版本的依赖 默认拉取master分支的依赖

image.png

Gomod

每次执行项目之前都可以执行以下 go tidy image.png

三、Go 语言工程实践之测试

如果评价项目的测试水准

代码覆盖率 一般覆盖率50%~60% 重要功能需要到80%

单元测试的两个目标稳定、幂等

基准测试

对代码进行性能分析

四、项目实践

1、需求描述

  • 展示话题和回帖列表
  • 仅实现后端服务
  • 数据存储在文件中

2、项目创建

web框架:Gin - github.com/gin-gonic/g…