并发
Go 最大的特色就是在语言层面天生支持并发,不需要像其他大多数编程语言那样需要开发者自行实现或借助第三方类库实现并发编程,Go 在语言级别支持的并发编程,其逻辑简化得通俗易懂简单好上手。
性能
不同于大多数脚本或解释性的高阶编程语言,用 Go 编写的代码直接了当编译成机器码高效执行。
简洁
25 个关键字即表达你能想到的所有招式,没有也不需要有任何多余,想干啥事就 go 一下。
跨平台
x86、AMD64 (x86_64)、ARM;Linux、Windows、Darwin (OSX)、FreeBSD、Android (计划Go 1.4) 几乎全平台支持,真正做到一份源码,随处编译,到处运行。
作为一个 Go 语言的重度用户来看,当前除了不适合拿来造操作系统以外在操作系统之上应用级的事情都能干。再更具体一点,比如说适用于这样一些使用场景:
系统应用
以前要用 C/C++ 做的系统应用,现在都可以用 Go 来写,事半功倍,而且 Go 完美包容 C 源代码,两者互相调用还可以混合编译从而无缝集成。
网络应用
包含了常见的服务端编程比如 Web 和 API Service,以前用 PHP / Python / Ruby / Java 干的事情现在都可以用 Go 更加简单清晰的来写。再比如还可以拿来做一些 Proxy(代理)如网络穿透软件等,你懂的。
分布式系统
基于 Go 强大的系统编程加网络编程,打造各种跨网络的分布式系统服务,Go 社区有不少和分布式系统相关的开源产物。
各种形态的存储和数据库应用
比如 groupcache,influxdb 等。
客户端应用
包括带界面的桌面软件,以及后续可以想像的移动端应用(比如对 Android 的支持)。
云服务(PaaS)
如基于 Go 打造的七牛云存储(分布式对象存储系统),比如基于 Go 编写的 Docker(一款开源的容器虚拟化产物)。
Go 能做的事情,包含但不限于以上罗列的使用场景。
我们主要使用 Go 开发了以下服务和工具:
总的来讲,Go 在我们七牛的工程中代码覆盖率超过 90% 。还有 10% 不能覆盖的原因是我们给开发者自助使用的 Web 界面需要用 JavaScript 编程来实现酷炫的前端,以及我们为开发者准备了多达超过 10 种编程语言的 SDK 。
Go 比较热门的开源项目,不完全罗列举例:
更多: https://code.google.com/p/go-wiki/wiki/Projects
用 Go 的公司,不完全罗列举例:
国外:
Google、YouTube、Dropbox、dotCloud、10gen、Apcera、Mozilla、Heroku、Github、Bitbucket、Bitly、CloudFlare、Cloud Foundry、Flipboard、Disqus、SendGrid、Tumblr、Zynga、Soundcloud
更多:https://code.google.com/p/go-wiki/wiki/GoUsers
国内:
七牛云存储、京东云平台、盛大云CDN、仙侠道、金山微看、Weico、西山居、美团、豆瓣、小米商城、360
更多:https://github.com/qiniu/go/issues/15
这是一个很有趣的话题,尤其是在今年6月份相继召开了 APPLE WWDC 2014 和 Google I/O 2014 两场举世闻名的互联网科技盛会后,APPLE 发布了用于 iOS 下一代编程的 Swift 语言,这给关注 Android 的开发者们留下了无限的遐想,尽管后来惊喜并没有如人们预期一样出现。作为一个纯洁的 Android 程序员,大概不会关注到 Go 将要支持 Android 的消息;作为一个无邪的 Go 程序员,大概也不会去关心 Android 开发和未来。但戏剧性的就是,我们当下就是处于这样一个各种跨界的大融合时代,没有什么不可能。
由于 Go 是跨平台编译的,早前就有在 ARM 上编译 Go 并成功运行的尝试。这个尝试是直接将用 Go 编写的源代码在 ARM 环境下编译,然后调用 adb shell 装入 Android 里边作为 Linux 下的可执行文件运行,但是没法关联支持 JNI(Java Native Interface),只能作为一个独立的进程运行,然后通过 RPC、TCP 等协议方式通信,相当于是一个 App 在运行方式上分成了两部分,这样非常不利于 App 的状态管理,所以此方式无法用 Go 编写出无缝结合的 Android 应用。
然而,单方面想要用 Go 语言封装 Android SDK 更是难以行通的:Android 原本用 Java 封装的 SDK,包含了海量的 API 接口。如果是手工封装会导致功能上的欠缺,自动封装会让 Go 语言变得丑陋不堪。不管用哪种方式,都很难快速实现。若是用 Go 再实现一遍 Android SDK 且还想期望能与 Java 等效,这几乎是不可能的事情。
但实际上,Android 系统提供了两种开发包:SDK 和 NDK。用 Go 移植 Android SDK 不通,还可以尝试走 Android NDK 。
Android NDK(Native Development Kit )是一套开发工具集合,允许开发者用像 C/C++ 语言那样实现应用程序的一部分。然后可以通过 JNI 实现 Java 代码与 NDK 动态库的无缝集成。
Go 内置 Cgo,使得 Go 和 C 之间可以无缝地互相转换和调用,以及代码混合编译。仅此一点,就可以看出至少也为 Go 进行 Android NDK 开发奠定了基础。当然,Go 可以进行的扩展尝试可可以更多。
后续的尝试是另辟蹊径走 Android NDK,借助其可以将动态库 .so 和 Java 代码一起打包成 apk 的机制,实现在 Android 上的无缝加载和运行。所以,问题简化成只要 Go 能够编译出 .so 动态库再通过 Android NDK 就可以实现开发 Android 应用程序了。
Go 是一门纯粹静态类型的编程语言,编译出来的二进制是静态的,如何构建动态库,这是一道坎。不过 Go 社区的欣欣向荣完全超出你我的想像,比如 Go 社区里边有人发布了个开源项目叫 Goandroid,一个扩展了 Go 的工具链和运行库来支持将 Go 代码创建动态库(*.so)的工具。另外一个开源项目 Mandala 则是在基于 Goandroid 的工具链构建了一套完善的用 Go 开发原生 Android 应用的开发框架。
Goandroid 和 Mandala 的出现已经让 Go 开发原生 Android 应用成为现实。 尽管这两个框架都是 Go 社区由个人发起的开源项目,Go 官方尚未参与,不过 Go 已经打开了 Android 的潘多拉魔盒。
另外,可以再来扒一扒和技术无关的业界新闻。
2014 年 5 月,一场已经持续 4 年的官司:关于“Google 在 Android 平台使用 Java 侵犯知识产权”一案,联邦法院判定 Oracle 获胜。
2014 年 6 月,APPLE 公司在 WWDC 2014 上发布 Swift 编程语言,用来替代 Objective-C 更高效地编写 iOS 和 OS X 程序。
2014 年 6 月,Google 公司 Go 语言开发团队成员 David Crawshaw 提议下一个 Go 版本 ( Go 1.4 ) 支持 Android 平台。这算是一个关于 Go 支持 Android 而言相当掷地有声的宣称。文献详见:http://golang.org/s/go14android
就目前而言,Go 支持 Android 后可以干啥。简单来讲,Go 以支持 Android NDK 编程作为切入点,自然是可以在 NDK 这层注入 Go 所能带来的新鲜活力,比如在异步的并发编程上用 channels 而不再是 callbacks 通讯,比如为游戏引擎提供底层的高性能支撑,比如跟多媒体相关的更丰富地处理。所以,可以想像的到 Go 是可以引领 Android NDK 迎来一片生机盎然的春天。
Go 支持 Android 这事当前看起来是 Go 的一厢情愿,而 Android 对此结合似乎还无动于衷。然而, Android 背负的包袱毕竟过重。Go 跃出的一小步,开启的必然会是 Android 海阔天空的一大步。
尽管 Go 是一门问世不久显得很新的编程语言,有很多质疑的声音认为新生的事物就是不成熟就此望而却步。但在我个人看来,考量成熟的因素并不完全取决于它所经历和走过的岁月,而是在于它是否可以被当下这个时代所需要并赋予厚望,以及其心智和能力是否能够承载并担当得起这份荣耀与责任。
在我们今天这个时代,是一个包含了 PC 互联网、移动互联网、物联网和云计算 “四世同堂” 的技术多元盛世。在不曾久远的过去,此前的数十年间,没有哪一门编程语言能够经得起此般岁月的几经摧残而长生不老。70 年代就开始基业长青的 C,书写了整个单机时代的辉煌,在硬件更新换代多核一度再翻成指数级更迭又如此瞬息万变的今天,C 那副认真憔悴的注目神情所表达的静静默守和激流勇退才终归得以明白它曾有过的卓绝。而 Java / Python / PHP / Ruby 此前彼后所纵横的 PC Web 时代,以当下之势在此不可逆转的时代背景下正似岁月如梭般地离我们渐行老去。而当移动互联网悄然踏至的那一时刻,Android 势如破竹般地野蛮生长搭救了 Java 一命并在其身上倾覆了所有,换来的却不过是一份难以割舍又无法言痛的沉重爱情,在被包养换主后的 Java 擦伤了贞洁之后不得不忍辱负重潸然泪行,而 Java 也从此难以走下一座叫作 “节操” 的断背深山。而和 Java 长得很像极帅的那位 JavaScript,意气风发一竿子捅到底逆袭了整个 Web 后端,讨得所有 Web 前端开发者的拥簇和狂欢,眼看高举全栈工程大旗就要翻手为云覆手为雨,却优秀得不懂克己错失风向与当下这个多核时代格格不入,曾一度与 HTML5 结队合唱 “轻应用就是未来” 这一出双簧,不料 Apple Swift 以迅雷不及掩耳之势以逆袭之道还治其逆袭之身;如今既生 Go,又何生 NodeJS,感慨 Node 君真是生不逢时。总之,问君能有几多愁,掐指一算,不知诸君该何去何从……
虽群雄逐鹿,现百家争鸣,然乱世必有新生。 Go 有如清水出芙蓉,一个曾在温柔的岁月里深沉熟睡,尔后随着换季时节的轻声絮语呼唤苏醒,然后起身刹那之间不经意惊艳了时光,此后就在此应时之季娇艳绽放,随后波光花影,激荡涟漪,满是春意盎然,勃勃生机。
时光往回倒流近二十年,那是 1995 年,有几位计算机泰斗,在白纸上画了一个圈,开启了分布式系统编程时代的春天。那时还在贝尔实验室参与九号计划(Plan9)的 Robert C. Pike(Plan9 操作系统和 UTF-8 的共同设计者,分布式编程语言 Limbo 作者) 和 Kenneth Lane Thompson(1983年图灵奖得主,创建了 UNIX 和 Plan9 操作系统,B 语言和 C 语言的共同设计者,UTF-8 的共同设计者),在此段工作经历中开发了分布式网络操作系统 Inferno,并在此之上实现了分布式编程语言 Limbo,这是能够追溯到最早和后来的 Go 在功能特性上比较相似的前身。随后这两位泰斗相继都加入了 Google 公司,在 2007 年 9 月,这两位 Unix 和 C 还有 UTF-8 的始祖成员,再加上 Javascript V8 引擎和 Java HotSpot 编译器的作者 Robert Griesemer 一起,这 3 人小组设计了最初的 Go 语言雏形。此后,Go 语言逐渐吸引了一些业界优秀人物比如 80 后程序员 Brad Fitzpatrick(Memcached 作者,OpenID 协定者)的加入,Go 的团队阵营逐渐壮大。从 2007 年 9 月作为一个 Google 20% 自由时间的一个实验项目;到 2008 年 5 月发展为 Google 100% 支持的全时项目;再到 2009 年 11 月;Google 首次对外公开透露 Go 的存在;以及 2012 年 3 月,Go 1.0 官方正式版问世;Go 的演变和发展简直始料未及,从开始到现在都是一如既往地突飞猛进,一发不可收拾。
如果说到 Java 曾经的流行,我们会联想到 SSH(Struts + Spring + Hibernate);如果提到 Python,也会联想到 Django;如果提到 Ruby,会联想到 Ruby on Rails;如果提到 JavaScript,会联想到 NodeJS;如果提到 PHP,更是一堆长江后浪推前浪前浪死在沙滩上的 Web 开发框架。这些编程语言社区的繁荣昌盛无一例外都和 Web 开发息息相关,且最终沉淀下来的都是各种五花八门各有千秋的众多 Web 开发框架。可以说,我们当前所面临和 Web 开发的技术选型,从未有过如此的繁荣。繁荣的背后,衬托的是一个大江东流去不复还的 PC Web 时代。
我们再来看看 Go 的社区,是多么地非同寻常和多样丰盛。我们之前列举过 Go 社区里边比较流行热门的开源项目:比如 Docker,是时下最流行和容器虚拟化相关的技术产物;比如 GroupCache ,是一个类似或代替 Memcached 的分布式内存缓存系统;比如 nsq,是一款处理海量并发的消息队列系统;再比如 etcd,是一套用于配置同步管理的分布式键值存储系统;以上这些都是和网络和系统服务以及分布式相关。再比如 Goandroid,是一个开发 Android NDK 应用的工具,是和移动开发相关的…… 总之,有太多创新的开源产物,而 Web 开发框架都不是主要重点。Go 几乎涵盖了和编程领域相关的所有点和面,在 Go 1.0 正式版出现后的两年时间里,基于 Go 可以枚举全面覆盖的开源项目超过了 1000 个。可谓是随风潜入夜,润物细无声。
从 Go 诞生的时代背景和团队阵容以及开源社区的繁荣来讲,Go 并不是新生不熟,而是后生可畏,且极有可能成为一统天下的集大成者。
我们再来看一些实际使用场景,比如 Web 开发。大多数编程语言之上的 Web 开发框架都是遵照 MVC 的处理流程去开发 Web 应用:Model 部分封装数据,Controller 部分处理业务逻辑,View 部分植入变量填充模板页面。而大部分 Web 框架关于 MVC 的三部分都是在 Server-side 处理,比如对 View 部分的处理都是在 Server-side 通过程序动态对模版变量求值后再拼接组装成 HTML 页面输出给浏览器去呈现。而 Go 开发 Web 应用,并不依赖任何 Web 开发框架,用内置的标准库就可以轻而易举地实现:比如使用 net/http
标准库就可以数行代码构建一个完整的 Web 骨架应用;再比如,通过关键字 struct
封装一个数据结构就可以表达原本 MVC 框架中需要用厚重的 ORM (Object-Relational Mapping) 才能表达的那部分。大道至简,这可以说是 Go 的哲学。在 View 这一层,Go 也有相应标准库提供支持,但更推荐的做法,是当下比较流行的 MVVM (Model-View-ViewModel):Server-side 只输出 JSON,浏览器 DOM 作为 View 层,前端 JavaScript 充当 Contoller 部分;这样,不仅减少了 Server-side 的资源消耗还有中间传输的网络流量,而且前端可以更灵活和更丰富,后端也可以更轻盈和更高效,也更有利于项目的分工和协作。 而 Go 对 JSON 的生成和输出,有数据测试表明异常高效(在 i7-2600K 处理器上针对所有编程语言包含开发框架总计约100个测试对比中,Go 的性能指标稳居第一,详见:http://t.cn/RvZHyKI)。以我个人喜好之见,后端用 Go 前端用 AngularJS 可以说是现今流行 MVVM 方式的 Web 开发之绝唱组合。所以,如有疑问 Go 适不适合用来做 Web 开发,我想答案很肯定的:不但可以而且更简单同时做得更出色甚至还可以做的更多。
我们再来看看当下硬件突飞猛进的多核时代,软件层面的编程语言都有哪些支持和作为。“人生苦短,我用 Python”,被喊了这么多年的标语,是有多少有追求和品味的程序员都热衷于 Python。我想大家可以做个实际测验:比如用 Python 写一个死循环程序,然后运行起来,过一小段时间看看 CPU 占用率是多少。测试结果会是什么呢,CPU 会占用 100% 吗?不好意思如果是那应该是单核,且还得是没有超线程支持的骨灰级 CPU 才行!在当下普遍的双核(甚至 4 核或 8 核) CPU 上,这个死循环跑满最多只会占用不超过 50% 的 CPU 资源。好吧,你会说我开多个线程并行来跑这个死循环不就可以吃满 CPU 了吗?我想测试结论可以很明确的告诉你,多线程的方式并行跑这个死循环可是连 50% 的 CPU 都吃不到,不信你可以试试,呵呵。无需我解释为什么,大家可以自行 Google 搜索看看 GIL (Global Interpreter Lock) 机理。也不是我特别拿 Python 举例,PHP / Ruby / NodeJS 的程序员们也可以来做做同样的测试,呵呵。总之,一个简单得不能再简单的死循环,程序上再怎么优化,跑起来都吃不满 CPU,你说我们都是这么有品味的程序员,到底都是在追求些什么呢?这些 PC Web 时代下的脚本语言或者字节码解释型的语言,几乎都由于线程安全问题而在语言级的并发机制上裹足不前。尽管 Ruby 实现了很华丽的纤程,NodeJS 实现了很光线的非阻塞 IO,但始终逃离不了单线程简单可依赖原则抑或多线程效率提升但伴随着各种问题困扰从而不得不折中取舍的桎梏。所以,大部分时候,语言层面没有根本性地解决并发问题,转而使用传统的多进程这一外援策略去解决并发需求以及变相地迎合这个多核时代。然而,硬件很快,软件很慢,摩尔定律在硬件行业的应验带给传统软件行业的红利已经走到了尽头。
我们再来看看 Go 在当下这个多核时代的作为。不得不说,Go 最大的特色就是在语言层面天然支持并发,在 Go 程序里边,你可以通过在⼀个函数调用前使用关键字 go 即可让该函数 func 运行成为一个独立的 goroutine,goroutine 可以理解成一种比线程更加轻盈更省开销的轻量级协程。Go 的并发模型就是通过系统的线程来多路派遣这些独立函数的执行,使得每个用关键字 go 执行调用的函数可以运行成为一个单位协程。当⼀个协程阻塞的时候,调度器就会自动把其他协程安排到另外的线程中去执行,从而实现程序的无等待并行化运行。且调度的开销非常小,单核 CPU 调度的规模不下于每秒百万次,这使得我们能够创建大量的 goroutines,从而可以很轻松地编写并发程序达到我们想要的目的。
同时,Go 在语言层面还引入了 channel 这一内置类型来实现并发执行体 goroutines 之间的消息传递,通信靠 channels 来传递消息。Go 遵循 CSP(Communicating sequential processes) 并发模型,通过通信来共享内存而不是用共享内存的方式进行通信。Go 的并发里边没有共享内存,更没有内存锁,这⼀切都有利于进行更为安全和简单的并行程序编写。
终有一日,你会感慨:“人生苦短,说 Go 就 Go”!
时代在快速跃迁,尤其是现在言必及多核和并发,我们所看到的那些 PC Web 时代下的脚本语言所堆砌的华丽不过是一些延续性追随,而且这种延续性的步伐会越来越沉重,最终还是苦不堪言。唯有 Go,在语言层面对并发和多核乃是纯天然的支持,原本就是一场应时而生顺时而为的土生土长,Go 所代表的是一种破坏性创新。而我们所经历的这个时代,正是处于一个时代被时代所颠覆的时代,在这样一个转折点,所有的延续性创新不过是杯水车薪,唯有破坏性创新,与时代共舞,才会产生革命性的颠覆。
我们还可以回顾下之前提到 Go 对 Android 移动端非侵入式的支持,几乎就是一场悄无声息的逆袭。
Go 很年轻,却已健壮成年。Go 被设计得简洁高效,Go 在语法层面有着清晰简洁却又高效的表达能力,是一个让开发者编写程序很开心同时又更有生产力的系统编程语言。Go 在语言层面有着良好的并发支持,使得用 Go 语言编写多核和分布式网络的应用程序简单容易许多。Go 内置新颖灵活的类型系统还可以很方便地编写和构建模块化程序。Go 是一门需要编译源码才能运行应用的纯静态强类型语言,这点保证的了程序的安全性和执行效率,且 Go 从程序源代码编译成机器码非常快。Go 的跨平台支持,使得用 Go 语言编写的程序可以在现今大多数操作系统上编译运行。Go 还自带垃圾回收的内存管理机制,并且支持强大的运行时反射。Go 是动静相宜的,在性能和安全性方面保留了静态语言的优点,在编程写法上,却有着动态语言的灵活与优雅。
Go 是划时代的,唯有 Go 能成为史诗之绝唱!Go 不是在颠覆,就是在逆袭!