go 基准测试 找不到函数_Go语言基础(十一)

f1809218d0b5e41a907528007257d13c.png

Go语言基础(十一)

一、并发安全和锁

二、HTTP客户端和服务端

三、单元测试

四、性能基准测试


一、并发安全和锁

在某些场景下可能会存在多个goroutine同时操作一个资源(临界区),这种情况会发发生竞态问题,举个例子:

package 

两个goroutine去累加变量x,这两个goroutine在访问和修改x变量的时候就会存在数据竞争。因此就需要锁。

1、互斥锁

互斥锁是一种常用的控制共享资源访问的方法。它能够保证同时只有一个goroutine可以访问共享资源,Go语言中通过sync包中的Mutex类型来实现互锁。sync.Mutex是一个结构体,值类型,给函数传参的时候需要传指针。修改上述代码。

var 

使用互斥锁能够保证同一时间有且只有一个goroutine进入临界区,其他的goroutine则在等待,如果有多个goroutine等待,下一次将在这些goroutine中随机选择一个进入临界区。

2、读写互斥锁

互斥锁是完全互斥的,但是很多场景下是读多写少,当并发地去读一个资源不涉及修改的时候是没有必要加锁的。读写锁在Go语言中使用sync包中的RWMutex类型。

package 

需要注意的是读写锁非常适合读多写少的场景,如果读写的操作差别不大,读写锁的优势就发挥不出来。

3、sync.WaitGroup

264ba72bba3281d572c354c7c1b841f5.png

4、sync.Once

Go语言中sync包提供了一个针对执行一次的场景的解决方案,sync.Once只有一个Do方法。

5、sync.Map

Go语言中内置的map并不是安全的。举个例子:

package 

我开启了2000个也没报错,不过为什么,反正这个就是不安全?

在Go语言中sync提供了一个开箱即用的安全版map,同时sync.Map内置了诸如Store、Load、LoadOrStore、Delete、Range等方法。

package 

6、原子操作

代码中加锁操作因为涉及内核切换上下文耗时、代价比较高,针对基本数据类型可以使用原子操作确保并发安全,Go语言中原子操作由内置的标准库sync/atomic提供。atomic提供了原子级别的内存操作。

二、HTTP客户端和服务端

Go语言内置的net/http包提供了HTTP客户端和服务端的实现。

1、http协议

超文本传输协议(HyperText Transfer Protocol)是互联网上最为广泛应用的一种网络传输协议。所有的www文件都必须遵守这个标准,设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。

2、http服务器端

get请求示例:使用net/http包编写一个简单的发送http请求的客户端:

package 

3、http客户端

package 

另一种形式:

package 

4、小结

对于http和网络编程只是初识。后续如果用到再仔细看看

三、单元测试

不写测试的开发不是好程序员。

Go语言中测试依赖于go test命令,go test是按照一定约定和组织的测试代码的驱动程序,在包目录内,所有以_test.go为后缀名的源代码文件都是go test测试的一部分,不会被go build编译到最终的可执行文件中。

在*_test.go文件中有三种类型的函数,单元测试函数、基准测试函数和示例函数。

afbf8e1748182b4e32f51ceb89dbfaa4.png

go test命令会遍历所有的*_test.go文件中符合上述命名规则的函数,然后生成一个临时的main包用于调用相应的测试函数,然后构建并运行、报告测试结果,最后清理测试文件中的临时文件。

1、测试函数示例

新建一个字符串分割功能的文件夹split_string,新建文件split.go,用于切割字符串:

package 

新建测试函数,split_test.go

package 

直接在终端中打开,然后执行go test命令或者go test -v命令。

2、测试组

package 

3、子测试

package 

cbb0385aa0a37315dd851978983275b4.png

单独跑其中一个测试:go test -run=测试名

2dc1312833106495f953851cc20f9ca3.png

4、测试覆盖率

测试覆盖率,测试中被至少被运行一次的代码占总代码的比例。Go提供了内置功能来检查 覆盖率,可以使用go test -cover,例如上面自测试的测试代码:

60cf99637a09b50c74cdda307cd3de9a.png

此外,Go还提供了一个额外-coverprofile参数,用来将覆盖率相关的记录信息输出到一个文件。例如:

8833f1de6e8e4ddd056bff724cff6553.png

然后执行go tool cover -html=c.out,使用cover工具来处理生成的记录,该命令会打开一个本地浏览器窗口生成一个html报告。

596c2870e201fe1e1d7347aa44fa5e0a.png

四、性能基准测试

5、基准测试

基准测试是在一定的工作负载之下检测程序性能的一种方法。基准测试并不会默认执行,需要增加-betch参数,所以使用go test -bench=Split命令执行基准测试。

func 

024635a803f44995b69a2a0db841bab1.png

BenchmarkSplit-12表示对Split函数进行基准测试,数字12表示GOMAXPROCS的值。

1000000和4420 ns/op表示每次调用Split函数耗时4420ns,这个结果是1000000次调用的结果。

还可以为基准测试添加-benchmem参数,来获得内存分配统计情况。

c771a4fcb0cf68c0ea428c7f80c5a183.png

其中,240B/op表示每次操作内存分配240字节,4 alloc/op表示每次操作进行4次内存分配。对Split函数优化如下:

func 

7a35e36502519d85e0be9873c966a838.png

2、性能比较函数

使用斐波那契举例:

package 

性能比较函数:

package 

执行go test -bench=Fib2,默认情况下,每个基准测试至少运行1s,如果Benchmark函数返回时没有到1s,则b.N会按1,2,5,10,20,50,...增加,并且函数再次运行。

d5c2421e547f2407f3990c986f268391.png

还可以使用-benchtime指定最小基准时间,强制执行,以产生更准确的结果。

3、重置时间

b.ResetTimer之前的处理不会放到执行时间里,也不会输出到报告中,所以可以在之前做一些不计划作为测试报告的操作,比如连接数据库的时间。例如:

func 

4、并行测试

func 

RunParallel会创建出多个goroutine,并将b.N分配给这些goroutine执行,其中goroutine默认值为GOMAXPROCS,如果用户需要增加CPU限制可以使用SetParallelism。RunParallel通常会与-cpu标志一同使用。

func 

943af2063b8e34fcd06fc2f0790572f5.png

还可以在测试命令后面添加-cpu参数如go test -bench=. -cpu 1来指定cpu的数量。

5、Setup和TearDown

测试程序有时需要在测试之前进行额外的设置setup或在测试之后进行拆卸teardown。

通过在*_test.go文件中定义TestMain函数来可以在测试之前进行额外的设置setup或在测试之后进行拆卸teardown操作。

func 

举个例子:

func 

ce91fbdac81953f8d232d96bf587175c.png

6、示例函数

编写示例函数的好处:

1、示例函数能够作为文档直接使用,例如基于web的godoc中能把示例函数与对应的函数或包关联。

2、示例函数只包含了//output:也是可以通过go test运行的可执行测试。

3、示例函数提供了可直接运行的示例代码,可以直接在http://golang.org的godoc文档服务器上使用GoPlayGround运行示例代码。

我是尾巴~

每日一句毒鸡汤:很多人的生活都是一望无际、广袤无垠,感觉朋友如星星点头般布满生命的天幕, 其实每颗星与星之间的距离却那么遥远。

本次推荐:

Download DiffDog​www.altova.com

继续加油~!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值