GO的一个优势特点
- go可以充分发挥多核优势,高效运行
语言进阶
1.1Goroutine
-
协程和线程的定义:
协程:用户态,轻量级线程,栈KB级别
线程:内核态,线程跑多个协程,栈MB级别
协程和线程的区别在于:一个线程可以多个协程,一个进程也可以单独拥有多个协程。线程进程都是同步机制,而协程则是异步。协程避免了无意义的调度,由此可以提高性能
eg:
func hello(i int){
println("hello goroutine:"+fmt.Sprint(i))
}
func HelloGoRoutine(){
for i :=0;i<5;i++{
go func (j int){
hello(j)
}(i)
}
time.sleep(time.Second)
}
解析:
- 它创建了5个goroutine并发运行hello函数。每个goroutine都会打印一条消息。最后,主goroutine会睡眠1秒钟以等待其他goroutine完成。
1.2CSP
CSP(Communicating Sequential Processes)是一种并发编程模型,用于描述两个独立的并发实体通过共享的通讯 channel(管道)进行通信。
- 注:推荐通过通信共享内存而不是通过共享内存而实现通信
1.3Channel
Go 语言中的通道具有以下几个特性:线程安全、阻塞式发送和接收、顺序性、可以关闭、缓冲区大小。
我们可以使用make函数创建一个通道,并通过<-操作符进行数据的发送和接收。通道可以具有不同的类型,用于限制发送和接收的数据类型。
缓冲用法:make(chan 元素类型,[缓冲大小])
- 无缓冲通道 make(chan int)
- 有缓冲通道 make(chan int,2)
eg:
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)
}
}
解析:
- 第一个子协程发送0-9数字
- 第二个子协程计算输入数字的平方
- 最后由柱协程输出最后的平方数
通道是一种特殊的数据结构,可以在不同的协程之间传递值。它提供了一种通过发送和接收操作进行同步的方式。通过使用通道,协程可以安全地发送数据到通道,其他协程可以从通道中接收到这些数据并进行处理。
1.4并发安全LOCK
go语言中有很方便的用于解决并发的安全性问题
lock.Lock()
lock.Unlock()
在 Lock 和 Unlock 之间的代码段称为资源的临界区(critical section),是线程安全的,任何一个时间点都只能有一个协程执行这段区间的代码。
测试
1.常见事故
- 营销配置错误
- 用户提现,幂等失效
- 代码逻辑错误,广告位被占
- 代码指针使用错误,导致app不可用
2.常用测试逻辑
回归测试->集成测试->单元测试
从左到右覆盖率逐层变大,成本逐层降低
3.1单元测试
- 单元测试规则:
- 所有测试文件以_test.go结尾
- func TestXxx(*tesing.T)
- 初始化逻辑放到TestMain中
3.1.1单元测试-Tips
- 一般覆盖率:50%-60%,较高覆盖率80%+
- 测试分支相互独立、全面覆盖
- 测试单元粒度足够小,函数单一职责
3.2单元测试依赖
在编写单元测试时,有时会遇到被测代码依赖于外部资源或其他组件的情况。这些依赖可能会影响测试的可靠性和可控性。
为了解决这个问题,可以使用 Mock 技术来模拟被测代码的依赖关系。Mock(见下文3.4) 可以帮助我们在测试中隔离被测代码,使测试更加可靠和可控。
3.3试文件处理
在测试中,有时需要处理文件,例如读取测试数据或写入测试结果。Go 语言的标准库提供了丰富的文件操作函数,可以帮助我们在测试中处理文件。
- 例如,可以使用
ioutil包中的ReadFile函数来读取文件内容:
data, err := ioutil.ReadFile("testdata.txt")
if err != nil {
// 处理错误
}
// 使用 data
- 也可以使用
os包中的Create和Write函数来创建并写入文件:
file, err := os.Create("testdata.txt")
if err != nil {
// 处理错误
}
defer file.Close()
_, err = file.Write([]byte("test data"))
if err != nil {
// 处理错误
}
3.4Mock
Mock 是一种测试技术,用于模拟代码中的依赖关系。它可以帮助我们在测试中隔离被测代码,使测试更加可靠和可控。
在 Go 语言中,可以使用第三方库来实现 Mock。例如,可以使用 gomock 库来快速创建 Mock 对象。
要为一个函数或方法打桩,可以使用 gomock 库提供的 EXPECT() 方法来定义期望的行为。例如:
ctrl := gomock.NewController(t)
defer ctrl.Finish()
m := NewMockMyInterface(ctrl)
m.EXPECT().MyMethod(gomock.Any()).Return(1)
快速Mock函数
- 为一个函数打桩
- 为一个方法打桩
3.5基准测试
基准测试(Benchmark)是一种测试方法,用于测量代码的性能。它可以帮助我们了解代码的运行效率,并为优化代码提供参考。
- 优化代码,需要对当前代码分析
- 内置的测试框架提供了基准测试的能力
基准测试过程:
- 运行
- 优化
Go 语言内置的测试框架提供了基准测试的能力。要编写基准测试,只需创建一个以 Benchmark 开头的函数,并接受一个 *testing.B 类型的参数。在函数体中,使用 b.N 来控制测试循环的次数。
func BenchmarkMyFunction(b *testing.B) {
for i := 0; i < b.N; i++ {
MyFunction()
}
}