Ready to Go!

最近几个星期里,我的工余时间基本全部放在学习和使用Go语言上了。这只螃蟹很好吃;向大家推荐。

————————-
对Go语言的总体感觉:
————————-

– Go语言的语法简单(语言的复杂程度小于C++和Java,关键词数量相当于C),

– Go程序的编译速度非常快。我尝试了两种Go编译器:

1. Rob Pike的GC编译器编译起来瞬间完成;

2. Ian Taylor的gccgo编译速度虽然不如GC,但是也快过g++,而且代码生成优化做的更好)

– 生成的代码的执行效率和g++的结果的可比。这个链接(http://shootout.alioth.debian.org/u64q/benchmark.php?test=all〈=go&lang2=gpp)比较了GC编译的Go程序和g++编译的C++程序的

– 执行时间(Go程序执行时间大于C++程序;但是基本在三倍之内),

– 内存消耗(C++程序和Go程序相当,有时Go程序内存消耗小,有时是C++程序消耗小)

– 代码行数(Go用的行数有时数倍少于C++)

– 随着gccgo加入gcc 4.6成为一种主流语言,加上Go语言语法相对于C++非常简单,可以预见未来Go编译器的效率可以大幅度追赶g++。

– 开发效率非常高。我之前用C++写的open source的LDA模型训练程序(http://code.google.com/p/ompi-lda),周末用Go重写了一遍(http://code.google.com/p/lda-go)。Go的版本的代码行数是 C++ 版本的 50%.

– 我从高一开始写C++程序,这么些年里对Java、Python之流是学懂了就烦了放弃了,只有对C++忠贞不二;但是用了Go之后,现在已经不想再用C++写程序了。

————————-
Go v.s. C++
————————-

这里我总结了一下我在实践过程中,从一个C++程序员的角度切换到Go的感觉:

Class

Go没有class的概念,但是可以做class做的事情 —— data members放在一个struct里;而Go语言允许为绝大部分data types配上一些methods —— 所以只要为这个struct配上一些methods,就成了“封装data和methods的class“。更细致的做法可以参见我的这篇博文:https://cxwangyi.wordpress.com/2011/03/19/go-method-v-s-c-class-member-functions,和这篇:https://cxwangyi.wordpress.com/2011/03/20/multiple-inheritance-go-v-s-c/

Class Hierarchy

Go不支持C++的多层继承,只支持从interface派生上述的struct。但是因为多个interfaces可以embedding,所以这样就能实现C++的多继承要做的事情了。而且逻辑简单清晰。关于Go的embedding机制,可以参见:http://golang.org/doc/effective_go.html#embedding

String

Go里,string是一种first class type。

UTF 和 XML

Go标准库里有全面完善的支持(http://golang.org/pkg/utf8, http://golang.org/pkg/utf16, http://golang.org/pkg/xml)

STL vector 和 map

在 Go 里,array 和 map 是两种 first-class types。其中array相当于vector,map相当于STL中的map。另外有一种叫做slice的类型,类似 vector::iterator。

Containers

Go的标准库里有对 heap(STL priority_queue),list(STL list),ring(circular list)和 vector 的支持。

Closure 和 Callback

C++不支持closure(虽然在C++0x里有),通常通过template和functor来实现 callback。Go支持closure就如同Scheme这样的functional programming languages一样。具体的例子可以参见我的这篇博文:https://cxwangyi.wordpress.com/2011/03/20/closure-in-go-c-and-scheme

Multi-threading 和 Synchronization

Go的一个重要特点就是支持goroutine,一种语言内置的multi-threading机制。Go的标准库里也有mutex,semophore之类的基本同步机制(http://golang.org/pkg/sync),但是不建议使用,因为CSP模型已经从数学上证明,利用fixed-sized blocking queue就能实现没有 race condition的 concurrency。Go提供一种特定的类型叫channel,就是fixed-sized blocking queue。更详细的信息可以参见:http://golang.org/doc/effective_go.html#parallel

Protocol Buffer

Google的一个开源项目goprotobuf(http://code.google.com/p/goprotobuf)提供了protocol buffer编译器(protoc)的一个插件,把proto文件翻译成Go程序。

Go进程间通信

Go的标准库里提供的RPC(http://golang.org/pkg/rpc)覆盖了protobuf buffer + stubby的功能,但是仅限于Go语言开发的多个进程之间的通信。

格式化输出(std::cout, sprintf and others)

Go的标准库(http://golang.org/pkg/fmt)提供了这些格式化输出的功能。

gflags

Go的标准库(http://golang.org/pkg/flag)提供了等价于gflags的功能。

glog

Go的标准库(http://golang.org/pkg/log)提供了相当于glog的功能。

HTTP Server

Go的标准库(http://golang.org/pkg/http)提供了方便的写HTTP server的功能。用它来实现 stubby 中的 formz 易如反掌。

Go的 self-compilation

Go的标准库(http://golang.org/pkg/go)提供了写一个Go程序,来解析另一个Go程序的能力。

从Go调用C/C++

Rob Pike的GC package里有一个工具叫cgo,可以让Go程序调用标准C程序。另一个更现实的路子是:SWIG从2.0版本开始支持Go,让Go程序能调用C/C++程序。如果用SWIG + Rob Pike的GC,那么可以把C/C++程序编译成一个shared library,然后Go程序在运行的时候链接之。但是在写分布式计算程序的时候,我们经常希望用静态链接——这样executable binary file虽然较大,但是不需要实现在机群中每台机器上保证部署相同版本的动态链接库。这种需求需要用 SWIG + Ian Taylor的gccgo编译器。我在32bit的Ubuntu Linux和64bit的SUSE Linux上都成功的编译了刚刚发布的GCC 4.6(其中包含gccgo),并且实验了SWIG + gccgo的方法。