【字节青训营-后端专场】Go 语言上手 - 工程实践

并发编程

并发vs并行
并发:多线程在一个核的cpu运行
并行:多线程在多个核的cpu运行

Goroutine

func hello(i int){
    .......
}
func HelloGoRoutine(){
    for i:=0;i<5;i++{
        go func (j int){
            hello(j)
        }(i)
    }
    time.Sleep(time.Second)//防止协程结束前 主进程结束
}

CSP 协程之间的通信

go提倡通过通信共享内存

Channel

make(chan int)//无缓冲通道
make(chan int,2)//有缓冲通道

无缓冲通道:同步通道,发送接收几乎同时
有缓冲通道:取走才能放
考虑子协程A,B A发送数字,B计算数字的平方,主协程输出
发现最终输出有序

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 {
        println(i)
    }
}

并发安全 Lock

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 Add(){
    x = 0
    for i := 0;i < 5; i++ {
        go addWithoutLock()
    }
    time.Sleep(time.Second)
    println(x)//10000
    x = 0
    for i := 0;i < 5; i++ {
        go addWithoutLock()
    }
    time.Sleep(time.Second)
    println(x)//可能<10000
}

WaitGroup

Add(delta int)//计数器+delta
Done()//计数器-1
Wait()//阻塞直到计数器为0

func hello(i int){
    .......
}
func HelloGoRoutine(){
    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()
    time.Sleep(time.Second)//防止协程结束前 主进程结束
}

依赖管理

GOPATH

环境变量 其下有
bin目录:项目编译的二进制文件
pkg目录:项目编译的中间产物,加速编译
src目录:项目源码

项目代码直接依赖src下的代码
go get下载最新版本的包到src目录下
无法实现package的多版本控制(package版本更新)

Go Vendor

增加vendor文件夹 先在vendor下寻找,再去GOPATH下寻找
依赖冲突导致编译错误

Go Module

通过go.mod文件管理依赖包版本
通过go get/go mod指令工具管理依赖包
go.mod:配置文件,描述依赖
Proxy:中心仓库管理依赖库
go get/go mod:本地工具

单元测试

规则

测试文件以_test.go结尾
func TestXxx( * testing.T)
初始化逻辑放到TestMain中

func HelloTom() string {
    return "Jerry"
}



func TestHelloTom(t *testing.T) {
    output := HelloTom()
    expectOutput := "Tom"
    if output != expectOutput {
        t.Error("Expected %s do not match actual %s",expectOutput,output)
    }
}

覆盖率

反映被测试函数被测试的函数占比
较高 80%+

项目实践

posted @ 2022-05-08 23:22  Frozen_Heart  阅读(91)  评论(0编辑  收藏  举报