如何得到goroutine 的 id?

使用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:

  1. 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)
  2. 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的方法。

阅读全文

超全的Go Http路由框架性能比较

使用Go开发Web应用非常方便,它自己的路由器default request multiplexer超级简单,但是功能也有限,所幸net/http库的设计非常好,很容易实现自己定义的路由器,所以你如果在github搜一下,会找到很多的第三方的路由库。

但是这些路由库良莠不齐,尤其是早期实现的路由器,有些实现了很差的路由算法,有些没有仔细考虑内存的分配,导致垃圾回收的问题。

Julien Schmidt在实现HttpRouter库的时候将测试代码抽象出一个测试框架,用来测试Go的各种的路由器,测试的库相当的全。这个测试框架放在了github上。

对于架构师和Go Web开发人员来说,这个测试确实是一份值得参考的资料,在选择一款路由框架的时候非常有帮助。

路由是Go Web框架的一个功能,它可以将不同的URL映射到相应的处理方法上。一些库只实现了路由的功能,也有一些库实现了完整的Web框架的特性,如上下文管理,Session的维护,模版的处理,ORM等。本文只比较路由的性能。

阅读全文

Golang序列化框架对决 - 为什么andyleap/gencode那么快?

我在github上创建了一个Go语言序列化/反序列化库的性能比较的项目gosercomp,用来比较常见的Go语言生态圈的序列化库。
性能是以Go官方库提供的JSON/XML序列化库为基准,比较一下第三库能带来多大的性能提升。
尽管一些第三方库会自动产生Struct的代码,我们还是都以下面的数据结构为例:

1
2
3
4
5
type ColorGroup struct {
Id int `json:"id" xml:"id,attr" msg:"id"`
Name string `json:"name" xml:"name" msg:"name"`
Colors []string `json:"colors" xml:"colors" msg:"colors"`
}

其中Colors是一个slice。我并没有测试Struct嵌套以及循环引用的情况。

目前本项目包含了以下几种序列化库的性能比较:

对于序列化库的实现来讲,如果在运行时通过反射的方式进行序列化和反序列化,性能不会太好,比如官方库的Json和Xml序列化方法,所以高性能的序列化库很多都是通过代码生成在编译的时候提供序列化和反序列化的方法,下面我会介绍MessagePackgencode两种性能较高的序列化库。

本项目受alecthomas/go_serialization_benchmarks项目的启发。

阅读全文

使用Go开发一个 Slack 运维机器人

受湾区日报的自动化机器人启发:湾区日报的第一个“员工”:Slack/Hubot, 我决定为自己的 side project 写一个自动化的slack运维机器人。

uriDB技术流是一个搜集高质量技术文章的网站。主要是由爬虫到一些技术站点寻找关注度高的技术文章,以及一些技术聚合站点的高质量的文章,我也会发一些平常自己看到的技术文章。uriDB也允许用户注册发布文章。

因为这是自己的 side project, 我不会将精力全部放在这个项目上。 如果有一个机器人,可以方便的维护这个站点,那么可以极大减少我的工作量。

这个网站后台完全是由 Go 开发的,所以我还是想用Golang实现这个机器人,而没有采用hubot + hubot-slack

目前这个机器人实现了基本的功能:

  • 发表一个文章链接
  • 修改文章的元数据
  • 删除文章
  • 分析一个文章链接

有时间我会将服务器性能监控等功能加上。

阅读全文

交叉编译Go程序

Go 1.5以前,交叉编译程序还是有一点麻烦的,你需要massive scripts t来编译和宿主机器不同的程序。

正如 comes with support for all architectures built in文章中介绍的, Go 1.5可就简单的多了,你只需设置 GOOSGOARCH 两个环境变量就能生成所需平台的Go程序。

比如使用下面的代码测试:

1
2
3
4
5
6
7
8
package main
import "fmt"
import "runtime"
func main() {
fmt.Printf("OS: %s\nArchitecture: %s\n", runtime.GOOS, runtime.GOARCH)
}

编译它: $ GOOS=darwin GOARCH=386 go build test.go
就可以生成运行在OS X上的程序。

阅读全文

几种Go序列化库的性能比较

序列化库在网络传输,RPC,数据库访问等环境中经常用到,它的性能的好坏直接影响着整个产品的性能。
本文列出了几种高性能的Go语言的序列化库,并通过一个简单的无循环引用的数据结构测试它们的性能。
测试代码: gosercomp at github

03/14/2016 更新。 增加Thrift/Avro/Gencode的性能比较。

阅读全文

Go 反射的规则

原文: The Laws of Reflection
翻译: 反射的规则 by mikespook 转载时略作修改

反射的规则

在运行时反射是程序检查其所拥有的结构,尤其是类型的一种能力;这是元编程的一种形式。它同时也是造成混淆的重要来源。

在这篇文章中将试图明确解释在 Go 中的反射是如何工作的。每个语言的反射模型都不同(同时许多语言根本不支持反射)。不过这篇文章是关于 Go 的,因此接下来的内容“反射”这一词表示“在 Go 中的反射”。

阅读全文

goreq: 极简单的流式golang http client

goreq是一个极其简单的流式golang http client。它是我寻找类似Java OKHttp库的golang http client库时创建的。
最原始的代码fork自gorequest,它实现了Node.js库SuperAgent类似的功能。但是gorequest有一些bug没有fix,用户也提出了一些新的特性没有支持。
我重构了代码,更正了一些bug,增加了新的特性,尤其是POST BODY现在可以支持任意类型, 不再局限于json或者form字符串格式。 因为改动比较大,不好提交pull requests,干脆创建了一个新的轮子。这就是这个项目的最初目的。

比如下面调用baidu API根据IP地址获取地理信息的例子:

1
2
3
4
5
headers := `{"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64; rv:40.0) Gecko/20100101 Firefox/40.0",
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Referer":"http://developer.baidu.com/map/index.php?title=webapi/ip-api"}`
_, body, _ := goreq.New().SetHeaders(headers).Get("http://api.map.baidu.com/location/ip?ak=E4805d16520de693a3fe707cdc962045&ip=202.198.16.3&coor=bd09ll").End()

阅读全文

如何编写Go代码

官方原文: How to Write Go Code,
根据最新官方文档翻译。翻译参考wang_yb如何写 go 代码
因为官方文档有更新,我根据新版本的文档重新进行了翻译。

本文演示如何开发一个简单的 go package, 以及 go tool 的使用方法,
即获取(fetch), 编译(build), 安装(install) go package 的标准方法和命令.

go tool 需要你按照一定的标准来组织代码. 请仔细阅读本文.
它介绍了用来构建和运行 Go 程序的最简单方法.

介绍本文的视频参照: https://www.youtube.com/watch?v=XCsL89YtqCs。

阅读全文

Go的50度灰:Golang新开发者要注意的陷阱和常见错误

原文: 50 Shades of Go: Traps, Gotchas, and Common Mistakes for New Golang Devs
翻译: Go的50度灰:新Golang开发者要注意的陷阱、技巧和常见错误, 译者: 影风LEY

Go是一门简单有趣的语言,但与其他语言类似,它会有一些技巧。。。这些技巧的绝大部分并不是Go的缺陷造成的。如果你以前使用的是其他语言,那么这其中的有些错误就是很自然的陷阱。其它的是由错误的假设和缺少细节造成的。

如果你花时间学习这门语言,阅读官方说明、wiki、邮件列表讨论、大量的优秀博文和Rob Pike的展示,以及源代码,这些技巧中的绝大多数都是显而易见的。尽管不是每个人都是以这种方式开始学习的,但也没关系。如果你是Go语言新人,那么这里的信息将会节约你大量的调试代码的时间。

阅读全文