Go语言上手-工程实践|青训营笔记

52 阅读1分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第2篇笔记

go内容简图: image.png

1.语言进阶

1.1并发与并行

简单理解图: image.png

go语言可以充分发挥多核优势,高效运行

协程与线程 image.png

协程:用户态,轻量级线程,栈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()
}

代码实现截图:

image.png

1.2 CSP

image.png

提倡通过通信共享内存而不是通过共享内存实现通信

1.3 Channel

image.png

用法:

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

运行结果截图:

image.png

运行结果分析:

image.png

在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
	}
}

结果截图:

image.png

此时我们可以看到 在数据量比较小的情况下 加锁和不加锁的结果是一样的

但是我们把数据量增加100倍之后

image.png

我们可以看到,加锁的结果是正确的,而不加锁的结果会明显的小了很多,造成了数据的缺失

1.5 WaitGroup

image.png

计数器开启协程+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)
}

运行结果:

image.png

代码分析:

首先创建一个WaitGroup wg

在wg里面增加5个协程

然后运行5个协程,每个协程运行结束时wg阻塞器中的值减一,当阻塞器中的值为0时,主程序运行,结束程序

2.依赖管理

image.png

  • 工程项目不可能基于标准库的0~1代码搭建
  • 管理依赖库

2.1 go的依赖管理

image.png

  • 不同环境(项目)依赖的版本不同
  • 控制依赖库的版本

image.png

  • 项目代码直接依赖src下的代码
  • go get 下载最新版本的包到src目录下

go mod 指令

image.png

2.2 依赖管理三要素

  • 配置文件,描述依赖 go.mod
  • 中心仓库管理依赖库 Proxy
  • 本地工具 go get/mod

3.测试

image.png

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

截图:

image.png

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.项目实践

因本人能力有限,实现不出来该项目。(萌新求放过)