html tool

显示标签为“golang”的博文。显示所有博文
显示标签为“golang”的博文。显示所有博文

2019年11月5日星期二

golang & gdb

https://stackoverflow.com/questions/25615421/golang-debug-using-gdb

Save that to main.go. Then compile with the follwing gcflag flag.
go build -gcflags "-N"
Open gdb with your newly built golang app
gdb gdbtest
# or 
gdb <PROJECT_NAME>

2019年9月24日星期二

golang array的定义和引用


 1 package main
  2 import "fmt"
  3     
  4 func qsort(data []int) {
  5     if len(data) <= 1 {
  6         return
  7     }
  8     mid := data[0]
  9     head, tail := 0, len(data)-1
 10     for i := 1; i <= tail; {
 11         if data[i] > mid {
 12             data[i], data[tail] = data[tail], data[i]
 13             tail--
 14         } else {
 15             data[i], data[head] = data[head], data[i]
 16             head++
 17             i++
 18         }
 19     }
 20     qsort(data[:head])
 21     qsort(data[head+1:])
 22 }   
 23     
 24 func main(){
 25     var arr = [...]int{1, 4, 8, 2, 55, 3, 4, 8, 6, 4, 0, 11, 34, 90, 23, 54, 77, 9, 2, 9, 4, 10};
 26     fmt.Println(arr)  //[popexizhi: 这个用%v,%s 很奇怪的效果可以试试啊:)]
 27     qsort(arr[:]) //[popexizhi: 这个是不一样之处,type *[22]int 和 type []int 不是一个类型的 ,
这里形参定义使用 []int ,调用时确定长度的数组要使用 arr[:] ]
 28     fmt.Println(arr)
 29 }   

参考:http://shouce.jb51.net/golang-doc/20.html

2019年3月29日星期五

转:go 基线测试



https://www.flysnow.org/2017/05/21/go-in-action-go-benchmark-test.html


[popexizhi: 原文的例子确实不错,测试了一下,感觉这个应该是函数/方法级别的很好用,可以用于方法对比的评估中。]

什么是基准测试

基准测试,是一种测试代码性能的方法,比如你有多种不同的方案,都可以解决问题,那么到底是那种方案性能更好呢?这时候基准测试就派上用场了。
基准测试主要是通过测试CPU和内存的效率问题,来评估被测试代码的性能,进而找到更好的解决方案。比如链接池的数量不是越多越好,那么哪个值才是最优值呢,这就需要配合基准测试不断调优了。

如何编写基准测试

基准测试代码的编写和单元测试非常相似,它也有一定的规则,我们先看一个示例。
itoa_test.go
func BenchmarkSprintf(b *testing.B){
 num:=10
 b.ResetTimer()
 for i:=0;i<b.N;i++{
  fmt.Sprintf("%d",num)
 }
}
这是一个基准测试的例子,从中我们可以看出以下规则:
  1. 基准测试的代码文件必须以_test.go结尾
  2. 基准测试的函数必须以Benchmark开头,必须是可导出的
  3. 基准测试函数必须接受一个指向Benchmark类型的指针作为唯一参数
  4. 基准测试函数不能有返回值
  5. b.ResetTimer是重置计时器,这样可以避免for循环之前的初始化代码的干扰
  6. 最后的for循环很重要,被测试的代码要放到循环里
  7. b.N是基准测试框架提供的,表示循环的次数,因为需要反复调用测试的代码,才可以评估性能
下面我们运行下基准测试,看看效果。
➜  hello go test -bench=. -run=none
BenchmarkSprintf-8      20000000               117 ns/op
PASS
ok      flysnow.org/hello       2.474s

运行基准测试也要使用go test命令,不过我们要加上-bench=标记,它接受一个表达式作为参数,匹配基准测试的函数,.表示运行所有基准测试。
因为默认情况下 go test 会运行单元测试,为了防止单元测试的输出影响我们查看基准测试的结果,可以使用-run=匹配一个从来没有的单元测试方法,过滤掉单元测试的输出,我们这里使用none,因为我们基本上不会创建这个名字的单元测试方法。[popexizhi: 这个-run=none 在pope本地的效果好像没什么不一样]
下面着重解释下说出的结果,看到函数后面的-8了吗?这个表示运行时对应的GOMAXPROCS的值。接着的20000000表示运行for循环的次数,也就是调用被测试代码的次数,最后的117 ns/op表示每次需要话费117纳秒。
以上是测试时间默认是1秒,也就是1秒的时间,调用两千万次,每次调用花费117纳秒。如果想让测试运行的时间更长,可以通过-benchtime指定,比如3秒。
➜  hello go test -bench=. -benchtime=3s -run=none
BenchmarkSprintf-8      50000000               109 ns/op
PASS
ok      flysnow.org/hello       5.628s

可以发现,我们加长了测试时间,测试的次数变多了,但是最终的性能结果:每次执行的时间,并没有太大变化。一般来说这个值最好不要超过3秒,意义不大。

性能对比

上面那个基准测试的例子,其实是一个int类型转为string类型的例子,标准库里还有几种方法,我们看下哪种性能更加。
func BenchmarkSprintf(b *testing.B){
 num:=10
 b.ResetTimer()
 for i:=0;i<b.N;i++{
  fmt.Sprintf("%d",num)
 }
}

func BenchmarkFormat(b *testing.B){
 num:=int64(10)
 b.ResetTimer()
 for i:=0;i<b.N;i++{
  strconv.FormatInt(num,10)
 }
}

func BenchmarkItoa(b *testing.B){
 num:=10
 b.ResetTimer()
 for i:=0;i<b.N;i++{
  strconv.Itoa(num)
 }
}
运行基准测试,看看结果
➜  hello go test -bench=. -run=none              
BenchmarkSprintf-8      20000000               117 ns/op
BenchmarkFormat-8       50000000                33.3 ns/op
BenchmarkItoa-8         50000000                34.9 ns/op
PASS
ok      flysnow.org/hello       5.951s

从结果上看strconv.FormatInt函数是最快的,其次是strconv.Itoa,然后是fmt.Sprintf最慢,前两个函数性能达到了最后一个的3倍多。那么最后一个为什么这么慢的,我们再通过-benchmem找到根本原因。
➜  hello go test -bench=. -benchmem -run=none
BenchmarkSprintf-8      20000000               110 ns/op              16 B/op          2 allocs/op
BenchmarkFormat-8       50000000                31.0 ns/op             2 B/op          1 allocs/op
BenchmarkItoa-8         50000000                33.1 ns/op             2 B/op          1 allocs/op
PASS
ok      flysnow.org/hello       5.610s

-benchmem可以提供每次操作分配内存的次数,以及每次操作分配的字节数。从结果我们可以看到,性能高的两个函数,每次操作都是进行1次内存分配,而最慢的那个要分配2次;性能高的每次操作分配2个字节内存,而慢的那个函数每次需要分配16字节的内存。从这个数据我们就知道它为什么这么慢了,内存分配都占用都太高。
[popexizhi: 这里的-benchmem,在本地测试的版本中为-test.benchmem ,我的测试版本是go1.11.4, 可能与原文的版本有出入吧:) ]
在代码开发中,对于我们要求性能的地方,编写基准测试非常重要,这有助于我们开发出性能更好的代码。不过性能、可用性、复用性等也要有一个相对的取舍,不能为了追求性能而过度优化。

2018年4月16日星期一

go gdb diff


https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/11.2.md

[popexizhi: gdb 太赞了,都可以debugger ,c++/py/go,看来要好好list了]

启动之后首先看看这个程序是不是可以运行起来,只要输入run命令回车后程序就开始运行,程序正常的话可以看到程序输出如下,和我们在命令行直接执行程序输出是一样的:
(gdb) run
Starting program: /home/xiemengjun/gdbfile 
Starting main
count: 0
count: 1
count: 2
count: 3
count: 4
count: 5
count: 6
count: 7
count: 8
count: 9
[LWP 2771 exited]
[Inferior 1 (process 2771) exited normally]