William Kennedy写了两篇关于Go 调试的文章,非常不错,特意翻译了一下,加深记忆。本文是其中的一篇: Stack Traces In Go。 另一篇是 Scheduler Tracing In Go。
Stack Trace表示堆栈跟踪,这是一个或多个堆栈帧的有序的集合。在程序出现panic的时候你会看到控制台有Stack Trace信息打印出来。
William Kennedy写了两篇关于Go 调试的文章,非常不错,特意翻译了一下,加深记忆。本文是其中的一篇: Stack Traces In Go。 另一篇是 Scheduler Tracing In Go。
Stack Trace表示堆栈跟踪,这是一个或多个堆栈帧的有序的集合。在程序出现panic的时候你会看到控制台有Stack Trace信息打印出来。
Channel是Go中的一个核心类型,你可以把它看成一个管道,通过它并发核心单元就可以发送或者接收数据进行通讯(communication)。
它的操作符是箭头 <- 。
|
|
(箭头的指向就是数据的流向)
就像 map 和 slice 数据类型一样, channel必须先创建再使用:
|
|
其它语言中Future和Promise的概念大量存在, 比如Node.js、Scala、Java、C#、C++ 11、Scheme、Swift等,可以方便的实现异步执行和回调。但是在Go语言的世界里,我们是通过goroutine/channel实现这种类似的功能呢,goroutine之间可以通过channel进行通讯, 但是,如果我们还是想使用Future/Promise的功能的话,该如何实现呢?
Future,Promise或Delay是用于并发编程的一种设计模式。它们表示一个对象,这个对象用来作为一次计算结果的代理,而该结果开始的时候是未知的,因为计算还没有完成。Promise与Future的区别在于,Future是Promise的一个只读的视图,也就是说Future没有设置任务结果的方法,只能获取任务执行结果或者为Future添加回调函数。
我们在监测Linux的应用的时候,当CPU的利用率非常高,但是系统的性能却上不去的时候,不妨监控一下线程/进程的切换,看看是不是context switching导致的overhead过高。
一般我使用dstat
工具用来监控,比如dstat -y
:
|
|
或者vmstat 3
:
|
|
但是如何知道那些进程/线程做切换能,淘宝褚霸有篇文章:latencytop深度了解你的Linux系统的延迟介绍了一种方法。事实上,有一个工具pidstat
,可以用来监控上下文切换。 它是sysstat包其中的一个工具,sysstat包含好几个很棒的工具,比如sar、iostat等。
执行pidstat -w
|
|
cswch/s
是主动地上下文切换,nvcswch/s
是被动执行上下文切换的次数。
如要要显示线程的上下文切换统计,可以执行:
|
|
更多的参数可以man pidstat
获得。
前几天我写了一篇文章: 超全的Go Http路由框架性能比较,利用Julien Schmidt实现的benchmark测试框架对几乎所有的go web框架的路由功能进行了比较。我本来以为对Go web框架的性能考察就告以段落了,直到我写了一段简单的代码测试Irsi,用来模拟实际产品中的处理,才发现了Julien Schmidt测试框架的问题。
这段代码是这样的:
|
|
当我将实际业务的处理时间模拟为10毫秒的时候,使用100并发进行测试:wrk -t16 -c100 -d30s http://127.0.0.1:8080/rest/hello
,Iris吞吐率才达到97 requests/second。详细介绍可以看我的文章: iris 真的是最快的Golang 路由框架吗? 。
虽然Iris的作者很快做了修改,临时解决了这个问题,但是也促使我重新审视Julien Schmidt测试框架,也促使我实现了一个测试Go web framework benchmak的框架: Go web framework benchmark。
2016/04/12 updated: 现在Iris已经改成了fasthttp实现,性能超级好。
原文: Golang自动生成版本信息
需求
golang程序在build时自动生成版本信息,使用 ./helloworld –version可以查看版本和build时间
实现原理
使用链接选项-X
设置一个二进制文件中可以访问的变量
依照我的前一篇文章(超全的Go Http路由框架性能比较)对各种Go http路由框架的比较, Iris明显胜出,它的性能远远超过其它Golang http路由框架。
但是,在真实的环境中,Iris真的就是最快的Golang http路由框架吗?
2016-04-05 更新: 我已经提交了一个Bug, 作者Makis已经做了一个临时的解决方案,性能已经恢复,所以准备使用Iris的读者不必担心。
根据我的测试,最新的Iris的测试如下:
- 在业务逻辑需要10毫秒时,吞吐率可以达到9281 request/s
- 在业务逻辑需要1000毫秒时,吞吐率可以达到95 request/s
性能已经很不错了。我会做一个其它路由框架的测试,看看其它的框架是否也有本文所说的问题。
使用Java的时候很容易得到线程的名字, 比如"Thread.currentThread().getName",这样就可以进行一些监控操作或者设置线程相关的一些数据。当转向Golang开发的时候,却发现Go语言并没有提供获取当前goroutine id的操作。这是Golang的开发者故意为之,避免开发者滥用goroutine id实现goroutine local storage (类似java的"thread-local" storage), 因为goroutine local storage很难进行垃圾回收。因此尽管以前暴露出了相应的方法,现在已经把它隐藏了。
Please don't use goroutine local storage. It's highly discouraged. In fact, IIRC, we used to expose Goid, but it is hidden since we don't want people to do this.
Potential problems include:
- when goroutine goes away, its goroutine local storage won't be GCed. (you can get goid for the current goroutine, but you can't get a list of all running goroutines)
- what if handler spawns goroutine itself? the new goroutine suddenly loses access to your goroutine local storage. You can guarantee that your own code won't spawn other goroutines,
but in general you can't make sure the standard library or any 3rd party code won't do that.thread local storage is invented to help reuse bad/legacy code that assumes global state, Go doesn't have legacy code like that, and you really should design your code so that state is passed explicitly and not as global (e.g. resort to goroutine local storage)
当然Go的这种隐藏的做法还是有争议的,有点因噎废食。在debug log的时候goroutine id是很好的一个监控信息。本文介绍了两种获取goroutine id的方法。