golang快速入门[1]-go语言导论

语言: CN / TW / HK

# golang快速入门[1]-go语言导论

## 声明

* 这是一套帮助初学者从0到1学习go语言的开源教程,致力于打造最完整、最强悍、最有深度的Go语言学习体系

* 我希望这套课程能够涵盖Go语言的所有体系、并致力于用大量的案例来诠释其用法

* 鉴于作者水平有限,真诚地希望能够集所有人的智慧,完善此项目,链接附后

## 简介

* Go(又称Golang)是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言

* Go的最初目标是消除Google软件开发的缓慢性和笨拙性,从而使流程更具效率和可扩展性,更多的关注于软件工程领域

* Go致力于解决当代大型工程项目面临的多核处理,网络系统,海量计算集群、快速构建等问题,Go在语言级别考虑并发问题,提供简单高效的并发编程

* 罗伯特·格瑞史莫(Robert Griesemer),罗勃·派克(Rob Pike)及肯·汤普逊(Ken Thompson)于2007年9月开始设计Go,稍后Ian Lance Taylor、Russ Cox加入项目

* Go是基于Inferno操作系统所开发的

* Go于2009年11月正式宣布推出,成为开放源代码项目,支持Linux、macOS、Windows等操作系统

* 在2016年,Go被软件评价公司TIOBE 选为“TIOBE 2016 年最佳语言”

* 很多重要的开源项目都是使用Go语言开发的,其中包括 Docker、Go-Ethereum、Thrraform、Kubernetes、etcd、hyperledger、tidb

## 基本语言的历史

* 1960年 Ken Thompson(肯.汤普森) 发明了B语言

* 1972年 Dennis Ritchie(丹尼斯·里奇)发明了C语言

* 1982年 Bjarne Stroustrup(本贾尼)发明了C++语言

* 1989年 Guido von Rossum 发明了Python语言

* 1995年SUN公司发明了Java语言

* 2007年Go语言诞生

* 2009年的11月对外正式发布

## Go语言创始人

对语言进行评估时,明白设计者的动机以及语言要解决的问题很重要。Go语言出自 Ken Thompson 和 Rob Pike、Robert Griesemer 之手,他们都是计算机科学领域的重量级人物。

* Ken Thompson

贝尔实验室 Unix 团队成员,C语言、Unix 和 Plan 9 的创始人之一,在 20 世纪 70 年代,设计并实现了最初的 UNIX 操作系统,仅从这一点说,他对计算机科学的贡献怎么强调都不过分。他还与 Rob Pike 合作设计了 UTF-8 编码方案

* Rob Pike

Go语言项目总负责人,贝尔实验室 Unix 团队成员,除帮助设计 UTF-8 外,还帮助开发了分布式多用户操作系统 Plan 9、Inferno 操作系统和 Limbo 编程语言,并与人合著了《The Unix Programming Environment》,对 UNIX 的设计理念做了正统的阐述

* Robert Griesemer

就职于 Google,参与开发 Java HotSpot 虚拟机,对语言设计有深入的认识,并负责 Chrome 浏览器和 Node.js 使用的 Google V8 JavaScript 引擎的代码生成部分

## go语言的继承

* Go语言有时候被描述为“C类似语言”,或者是“21世纪的C语言”

* Go从C语言继承了相似的表达式语法、控制流结构、基础数据类型、调用参数传值、指针等思想

* Go继承了C语言一直所看中的编译后机器码的运行效率以及和现有操作系统的无缝适配

* Go语言的家族树中还有其它的祖先。其中一个有影响力的分支来自Niklaus Wirth所设计的Pascal语言

* Modula-2语言激发了包的概念,然后Oberon语言摒弃了模块接口文件和模块实现文件之间的区别。第二代的Oberon-2语言直接影响了包的导入和声明的语法,还有Oberon语言的面向对象特性所提供的方法的声明语法等

* Go语言的另一支祖先,带来了Go语言区别其他语言的重要特性,灵感来自于贝尔实验室的Tony Hoare于1978年发表的鲜为外界所知的关于并发研究的基础文献顺序通信进程(communicating sequential processes,缩写为CSP)

在CSP中,程序是一组中间没有共享状态的平行运行的处理过程,它们之间使用管道进行通信和控制同步。不过Tony Hoare的CSP只是一个用于描述并发性基本概念的描述语言,并不是一个可以编写可执行程序的通用编程语言

Rob Pike和其他人开始不断尝试将CSP引入实际的编程语言中。他们第一次尝试引入CSP特性的编程语言叫Squeak,是一个提供鼠标和键盘事件处理的编程语言,它的管道是静态创建的

然后是改进版的Newsqueak语言,提供了类似C语言语句和表达式的语法和类似Pascal语言的推导语法。Newsqueak是一个带垃圾回收的纯函数式语言,它再次针对键盘、鼠标和窗口事件管理。在Newsqueak语言中管道是动态创建的,属于第一等公民,可以保存到变量中

在Plan9操作系统中,这些优秀的想法被吸收到了一个叫Alef的编程语言中。Alef试图将Newsqueak语言改造为系统编程语言,但是因为缺少垃圾回收机制而导致并发编程很痛苦

注:在Aelf之后还有一个叫Limbo的编程语言,Go语言从其中借鉴了很多特性。具体请参考Pike的讲稿:http://talks.golang.org/2012/concurrency.slide#9

* Go语言的其他的一些特性零散地来自于其他一些编程语言;比如iota语法是从APL语言借鉴,词法作用域与嵌套函数来自于Scheme语言和其他很多语言

* Go中也有很多创新的设计,比如Go语言的切片为动态数组提供了有效的随机存取的性能,还有Go语言新发明的defer语句

## go语言的特点

所有的编程语言都反映了语言设计者对编程哲学的反思,通常包括之前的语言所暴露的一些不足地方的改进。

* 简洁

Go项目是在Google公司维护超级复杂的几个软件系统遇到的一些问题的反思(但是这类问题绝不是Google公司所特有的)

正如Rob Pike所说,“软件的复杂性是乘法级相关的”,通过增加一个部分的复杂性来修复问题通常将慢慢地增加其他部分的复杂性

通过增加功能、选项、配置是修复问题的最快的途径,但是这很容易让人忘记简洁的内涵,卽使从长远来看,简洁依然是好软件的关键因素

简洁的设计需要在工作开始的时候舍弃不必要的想法,并且在软件的生命周期内严格区别好的改变或坏的改变。通过足够的努力,一个好的改变可以在不破坏原有完整概念的前提下保持自适应

而一个坏的改变则不能达到这个效果,它们仅仅是通过肤浅的和简单的妥协来破坏原有设计的一致性。只有通过简洁的设计,才能让一个系统保持稳定、安全和持续的进化

附带了相关的工具和标准库

没有隐式的数值转换

没有构造函数和析构函数

没有运算符重载

没有默认参数

没有继承

没有泛型(go2中考虑加入)

没有异常,即没有与错误处理相关的控制结构

没有宏

没有函数修饰

没有线程局部存储。

没有指针运算

没有类型别名

数组边界总是受到检查

* 基本特性

自动垃圾回收

包管理

函数作为一等公民

系统调用接口

只读的UTF8字符串

函数多返回值

匿名函数和闭包

反射

静态链接

严格的依赖规范

CSP并发编程

Goroutine协程

接口类型

* 向后兼容

Go语言本身是成熟和稳定的,而且承诺保证向后兼容:用之前的Go语言编写程序可以用新版本的Go语言编译器和标准库直接构建而不需要修改代码

* 类型系统

相比较于js、python,Go语言的类型系统避免动态语言中那些粗心的类型错误。但是Go语言的类型系统相比传统的强类型语言又要简洁很多,虽然有时候这会导致一个“无类型”的抽象类型的概念

Go语言程序员并不需要像C++或Haskell程序员那样纠结于具体类型的安全属性。在实践中Go语言简洁的类型系统给了程序员带来了更多的安全性和更好的运行时性能

Go语言遵循当代计算机系统设计的原则,特别是局部的重要性。Go的内置数据类型和大多数的标准数据结构都经过精心设计而避免显式的初始化或隐式的构造函数,因此内存分配和内存初始化代码被隐藏在库代码中了

Go语言的聚合类型(结构体和数组)可以直接操作它们的元素,只需要更少的存储空间、更少的内存分配,而且指针操作比其他间接操作的语言也更有效率

* 并发支持

由于现代计算机是一个并行的机器,Go语言提供了基于CSP的并发特性支持。Go语言的动态栈使得轻量级线程goroutine的初始栈可以很小,因此创建一个goroutine的代价很小,创建百万级的goroutine完全是可行的。

Go并发的座右铭:不要通过共享内存进行通信,而要通过通信共享内存(Don't communicate by sharing memory, share memory by communicating)

* 自动垃圾回收机制

对于系统语言,垃圾回收可能是一个有争议的功能

Go没有显式的内存释放操作:分配的内存返回池的唯一方法是通过垃圾回收器。

内存管理对语言在实践中的工作方式具有深远的影响。在C和C++中,太多的编程工作花费在内存分配和释放上

由于垃圾回收机制,语言更易于使用。

垃圾回收会带来巨大的成本:常规开销,延迟和实现的复杂性

知识渊博的程序员可以限制收集器所承受的压力,从而提高性能。(此外,Go安装附带了用于研究正在运行的程序的动态内存性能的良好工具)

自动垃圾回收算法是一个持续跟新的过程、活跃的开发领域

* 强大的标准库与规范

Go语言的标准库,提供了清晰的构建模块和公共接口,包含I/O操作、文本处理、图像、密码学、网络和分布式应用程序等,并支持许多标准化的文件格式和编解码协议

库和工具使用了大量的约定来减少额外的配置和解释,从而最终简化程序的逻辑,而且每个Go程序结构都是如此的相似,因此Go程序也很容易学习

Go语言自带工具构建Go语言项目只需要使用文件名、标识符名称以及少量的注释确定所有的库、可执行文件、测试、基准测试、案例、以及特定于平台的变量、项目的文档等;Go语言源代码本身就包含了构建规范

* 开源,活跃的社区

* 组成而不是继承

Go采用一种不寻常的方法来进行面向对象的编程(接口),它允许有相同方法的任何类型继承,而不仅是类

Go没有任何形式的基于类型的继承,这意味着没有类型层次结构

这是一个故意的设计选择,尽管类型层次结构已用于构建许多成功的软件,但Go认为该模型已被过度使用

## Go语言的优势

* 学习曲线容易,语法简单清晰

单就类型和规则而言,Go 与 C99、C11 相似之处颇多,这也是Go语言被冠以“NextC”名号的重要原因。

Go语言的语法规则严谨,没有歧义,更没什么黑魔法变异用法。

任何人写出的代码都基本一致,这使得Go语言简单易学。放弃部分“灵活”和“自由”,换来更好的维护性

* 强大的标准库和工具链

完整的工具链对于日常开发极为重要。Go 在此做得相当不错,无论是编译、格式化、错误检查、帮助文档,还是第三方包下载、更新都有对应的工具

内置完整测试框架,其中包括单元测试、性能测试、代码覆盖率、数据竞争,以及用来调优的 pprof,这些都是保障代码能正确而稳定运行的必备利器

可通过环境变量输出运行时监控信息,尤其是垃圾回收和并发调度跟踪,可进一步帮助我们改进算法,获得更佳的运行期表现

* 自动垃圾回收机制

垃圾回收一直是个难题。早年间,Java 就因垃圾回收低效被嘲笑了许久,后来 Sun 连续收纳了好多人和技术才发展到今天。可即便如此,在 Hadoop 等大内存应用场景下,垃圾回收依旧捉襟见肘、步履维艰

相比 Java,Go 面临的困难要更多。因指针的存在,所以回收内存不能做收缩处理。幸好,指针运算被阻止,否则要做到精确回收都难

每次升级,垃圾回收器必然是核心组件里修改最多的部分。从并发清理,到降低 STW 时间,直到 Go 的 1.5 版本实现并发标记,逐步引入三色标记和写屏障等等,都是为了能让垃圾回收在不影响用户逻辑的情况下更好地工作

* 静态链接

运行时、依赖库直接打包到可执行文件内部,简化了部署和发布操作,无须事先安装运行环境和下载诸多第三方库

* 编译迅速

* 清晰的依赖关系

* 并发编程

在早期 CPU 都是以单核的形式顺序执行机器指令。Go语言的祖先C语言正是这种顺序编程语言的代表

随着处理器技术的发展,单核时代以提升处理器频率来提高运行效率的方式遇到了瓶颈,单核 CPU 发展的停滞,给多核 CPU 的发展带来了机遇

现代计算机都拥有多个核,但是大部分编程语言都没有有效的工具让程序可以轻易利用这些资源。编程时需要写大量的线程同步代码来利用多个核,很容易导致错误

Go语言正是在多核和网络化的时代背景下诞生的原生支持并发的编程语言。Go语言从底层原生支持并发,无须第三方库,开发人员可以很轻松地在编写程序时决定怎么使用 CPU 资源

Goroutine 是 Go 最显著的特征

Go语言的并发是基于 goroutine 的,goroutine 类似于线程,但并非线程。可以将 goroutine 理解为一种虚拟线程。Go语言运行时会参与调度 goroutine,并将 goroutine 合理地分配到每个 CPU 中,最大限度地使用 CPU 性能

Go用类协程的方式来处理并发单元,却又在运行时层面做了更深度的优化处理。这使得语法上的并发编程变得极为容易

无须处理回调,无须关注线程切换,仅一个关键字,简单而自然

搭配 channel,实现 CSP 模型。将并发单元间的数据耦合拆解开来,各司其职,这对所有纠结于内存共享、锁粒度的开发人员都是一个可期盼的解脱

* 内存分配

Go 选择了 tcmalloc,它本就是为并发而设计的高性能内存分配组件

刨去因配合垃圾回收器而修改的内容,内存分配器完整保留了 tcmalloc 的原始架构。使用 cache 为当前执行线程提供无锁分配,多个 central 在不同线程间平衡内存单元复用

heap 则管理着大块内存,用以切分成不同等级的复用内存块。快速分配和二级内存平衡机制,让内存分配器能优秀地完成高压力下的内存管理任务

## Go语言擅长的领域

* Go语言主要用作服务器端开发,适合于多人周期较长的大型软件和支持云计算的网络服务

* 在服务器编程方面,Go语言适合处理日志、中间件、数据打包、虚拟机处理、文件系统、分布式系统、数据库代理等

* 网络编程方面,Go语言广泛应用于 Web 应用、API 应用、下载应用等

* 此外,Go语言还可用于内存数据库和云平台领域,目前国外很多云平台都是采用 Go 开发

* 由于Go垃圾回收牺牲了一些性能,因此其不适合做操作系统编程以及对速度要求极致的程序,不适合直接处理数据分析与计算

## 使用Go语言的公司

参见[世界上使用Go语言的企业](https://github.com/golang/go/wiki/GoUsers)

* Google

作为创造了Go语言的 google 公司,当然会力挺Go语言了。Google 有很多基于 Go 开发的开源项目,比如 kubernets,docker,大家可以参考《哪些项目使用Go语言开发》一节了解更多的Go语言开源项目

* Facebook

Facebook 也在使用Go语言,为此他们还专门在 Github 上建立了一个开源组织 facebookgo。大家可以通过 https://github.com/facebookgo 访问查看 facebook 开源的项目,其中最具代表性的就是著名平滑重启工具 grace

* 腾讯

腾讯在 15 年就已经做了 Docker 万台规模的实践。因为腾讯主要的开发语言是 C/C++ ,所以在使用Go语言方面会方便很多,也有很多优势,不过日积月累的 C/C++ 代码很难改造,也不敢动,所以主要在新业务上尝试使用 Go

* 百度

百度主要在运维方面使用到了Go语言,比如百度运维的一个 BFE 项目,主要负责前端流量的接入,其次就是百度消息通讯系统的服务器端也使用到了Go语言

* 七牛云

七牛云算是国内第一家选Go语言做服务端的公司。早在 2011 年,当Go语言的语法还没完全稳定下来的情况下,七牛云就已经选择将 Go 作为存储服务端的主体语言

* 京东

京东云消息推送系统、云存储,以及京东商城的列表页等都是使用Go语言开发的

* 小米

小米对Go语言的支持,在于运维监控系统的开源,它的官方网址是 http://open-falcon.org/。此外,小米互娱、小米商城、小米视频、小米生态链等团队都在使用Go语言

* 360

360 对Go语言的使用也不少,比如开源的日志搜索系统 Poseidon,大家可以通过 https://github.com/Qihoo360/poseidon 查看,还有 360 的推送团队也在使用Go语言

除了上面提到的,还有很多公司开始尝试使用Go语言,比如美团、滴滴、新浪等。

## Go语言吉祥物

Go语言有一个吉祥物,在会议、文档页面和博文中,大多会包含下图所示的 Go Gopher,这是才华横溢的插画家 Renee French 设计的,她也是 Go 设计者之一 Rob Pike 的妻子。

![image](../image/1.jpg)

## 参考资料

* [项目链接](https://github.com/dreamerjackson/theWayToGolang)

* [My Blog](https://dreamerjonson.com/)

* [Go源码](https://github.com/golang)

* [Go官网](https://golang.org/)

* [优秀的Go语言项目](https://github.com/avelino/awesome-go)

* [Bell Labs and CSP Threads](https://swtch.com/~rsc/thread/)

* [Go语言简介](http://c.biancheng.net/view/1.html)

* [The Go Programming Language](https://github.com/KeKe-Li/book/blob/master/Go/The.Go.Programming.Language.pdf)

* [Go FAQ](https://golang.org/doc/faq)

* [Go at Google: Language Design in the Service of Software Engineering](https://talks.golang.org/2012/splash.article)

分享到: