GopherChina

4 22

第三届 GopherChina 大会

上周末参加 GopherChina 第三届大会,感受不错。经过三年时间,Go 的发展非常火爆。会议规模从原来的几百人到上千人,还有很多站在座位两侧听的朋友。大会的内容也是从 Go 本身,到架构,到容器等相关领域都有涉及,可以说干货不错。办大会大会是一件辛苦事,非常感谢 Astaxie 一直以来的努力。讲好一个主题,也会需要很多技巧的,也非常感谢参与大会的各个讲师。言归正传,来聊聊大会的内容。

语言上 的 Go

每种语言都有自己的特色,Go 也不例外。学习 Go 的时候,难免会带入别的语言经验,造成一定的麻烦。因此从 Go 的方式来理解 Go,是 Go 语言开发者必须经历的过程。Tony Bai 从 Go 语言的角度,分享了 Go 的思维模式。

Go is about orthogonal composition of simple concepts with preference in concurrency.
Go 是在偏好并发的环境下的简单概念/事物的正交组合

从这句话就可以总结出几个 Go 开发的原则:

  • 事物的简单化,逻辑单元不要太大;不是一个函数从头到尾,是多个小函数组合起来的大函数
  • 正交组合,逻辑单元之间的无关性;因为函数之间的无关性,才可以复用,也才可以并发
  • 并发背景的需要,即业务是可以同时的,不是线性的

这一些原则还是需要很多的开发技巧来实现的,比如接口的垂直组合,如:


type ReadWriter interface {
    Reader // 这里体现了逻辑单元的简单化
    Writer
}

根据接口来更适配的接受逻辑水平扩展:


func ReadAll(r io.Reader) ([]byte, error)
// 可以支持文件流,网络数据流等
ReadAll(*os.File)
ReadAll(*http.Response.Body)

最后我比较感兴趣的就是 error 处理的内敛,比如:


// *bufio.Writer
func (b *Writer) Write(p []byte) (nn int, err error) {
    if b.err != nil {
        return nn, b.err  // 错误在结构内部
    }
    ... ...
}

// usage
buf := bufio.NewWriter(fd)
buf.WriteString("hello, ") // 这样就不需要每行 if err != nil
buf.WriteString("gopherchina ")
buf.WriteString("2017")
if err := buf.Flush() ; err != nil {
    return err
}


上面提到接口的垂直扩展,francesc 的分享就更深入的聊了 Go 中 interface{} 的使用技巧。interface{} 我的理解有两个意思。当 interface{} 带有方法的时候,是行为的定义,如:


type Reader interface{
    Read(data []byte)(n int,err error) // 注意定义的时候写一下变量名,否则不是啥意思
}

这样的接口就可以弥补 Go 没有泛型的不足。泛型的时候返回如 <List,Map> 其实是不对的,真正的意义很可能是 <Iterator>。在 Go 的编程中就逼迫你需要这样的思维来理解,找出需要泛型的时候数据类型的共通之处,执行相同的操作(如果就是不同的行为,写俩函数不是更好?)。

interface{} 另一个特殊场景就是空接口,对应的代码就是需要类型推断:

func do(v interface{}){
    switch t := v.(type){
        case int:
            fmt.Printf("int - %d",t)
        case error:
            fmt.Printf("error - %s",t.Error())
        default:
            fmt.Printf("interface - %v",t)
    }
}

不到万不得已不要这么写代码。否则需要推断类型的 case 越来越多,代码可维护性瞬间下降。


ezbuy 的分享有很多微服务相关的内容,选型 gRPC 的使用,context tracing 等问题。不过我最在意的是他们的开发环境搭建工具 Goflow。Go 的包管理机制一直为人所诟病。就算 vendor 解决了一些第三方包依赖的问题,但是非常的粗糙和直接。同时项目管理时 GOPATH 中既有第三方库,又有自己的项目代码,也给工程实践造成麻烦。Goflow 从分享中看很像 gb + package registry。Goflow 修改系统变量 GOPATH 到当前目录,再从内网 registry 下载第三方包到 vendor 目录。真的非常方便,是个不错的解决方案。而且国内网络访问很多包资源不是很顺畅,内网有 registry 提供很大的便利。这一套东西在公司内部使用我觉得非常棒。

另外他是唯一提及用 internal 包的分享。例如代码结构:

--product
  |
  |---internal
  |   |
  |   |---product_get.go
  |   |---product_search.go
  |   |
  |---product.go

代码和功能更加清晰明确。回头我也尝试一下这样的使用技巧。

4 19

第二届 Gopher China 大会

又一次,和同事去参加 GopherChina 2016 大会,了解 Go 语言相关的最新动态。和一年前不同,Go 语言已经受到许多企业青睐。一些知名企业开始使用 Go 语言开发。因而,本届大会更多的内容注重在 Go 实现的业务场景和架构上。

Go 与 高并发服务

Go 语言的 goroutine 特性,非常适合开发高并发网络服务。大会有几个题目聊起相关的内容。

百度前端接入团队分享了《Go在百度BFE的应用》。相关的内容其实在InfoQ有过分享。百度的服务体量太过巨大(日均千亿),代码优化手段 + Go的版本更新 对服务整体的提升作用不大,只能用特殊的措施 ———— 车轮大战。关闭 runtime 的GC,由代码根据目前程序的运行情况判断是否手动 runtime.GC()。以 master-worker的模式轮换正在服务和正在GC的程序。这种架构估计只有百度这种规模才用得上吧。但是私下的交流来说,小伙伴还是觉得 nginx + C 模块更适合。况且BFE之前那套也就是C写的,有足够的技术实力。

对比的来看是,吴小伟(skoo)的《Go在阿里云CDN系统的应用》。阿里 CDN 的网络接入系统还是 C 语言写的。CDN 的日志系统、调度系统和刷新系统是 Go 写的。这些业务对 Go 语言的 GC 不敏感,加上 Go 比 C 更简洁的语法特性,更快的开发效率,开发周围系统是很适合的。这里可以看到,同样是大流量系统,思考的角度也有不同。顺便说一下,skoo 是比较早研究 Go 语言的技术大神之一,博客有一些关于 Go 核心原理的文章。

4 29

第一届 Gopher China 大会

前两天去上海参加 Gopher China 2015 大会,见到很多久闻大名的大神和朋友,感觉很好。而且看到许多的企业,尤其是大企业都已经开始成规模的使用 golang,说明 golang 本身的设计和性能,已经受到了大家的认可。当然其实有很多的话题,不局限在 golang 了。

Go 语言核心

最重量级的话题,就是 雨痕 的 《Go 1.4 Runtime》。主要说了 Go 的内存分配器、垃圾回收器和goroutine调度器三块内容。我之前阅读过他的 《Go 语言笔记》 ,非常不错。很详细的阐述了 Go 语言本身的实现设计,同时为更合理的利用 golang 提供一些参考。 再加上他本人也很低调,真的是 隐士高人 的感觉。这次的他的演讲也相当不错。流畅的思路和平和的语言,而且不时的有诙谐幽默,让人听起来很有意思。唯一的遗憾是,他准备的ppt其实可以讲到3个小时,可惜会程只有45min,尽管大家还是争取多听了一些,但还是意犹未尽。

另一个超级话题,是 Robert Griesemer 的演讲。他是 Go 的三位作者之一,也是 Google V8 和 Java Hotspot VM 开发者之一,相当巨大的光环!他的演讲是关于 gofmt 的。 Go语言本身有很多的外围工具,比如 gofmt, godoc。其中格式化工具 gofmt 帮助大家简单直接的就统一了代码风格。Go 本身就带有 parser 包,就能够很好的去解析go源码到语法树。 唯一要吐槽的是 Q&A 环节,提问的童鞋用谁都听不懂的“英语”去问,哈哈哈!