一. Go语言简介

中文官网:https://golang.google.cn/

Go语言是谷歌公司于2009年11月发布的编程语言,其发明人Robert Griesemer、Rob Pike、Ken Thompson

  • Robert Griesemer:罗伯特·格瑞史莫参与开发Java的Hotspot编译器和Javascript V8引擎
  • Rob Pike:罗布·派克曾是Unix团队成员,与Thompson一起创造了UTF-8
  • Ken Thompson:肯·汤普森,IT行业殿堂级人物.1983年图灵奖和1998年美国国家技术奖.创造出C语言和Unix系统

官方解释:Go语言是一种开源的程序设计语言,它的目的使得开发者可以方便地构建简单、可靠、高效的软件

二. Go语言特性

语法简单

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

Go语言的语法处于简单和复杂的两极。C语言简单到你每写下一行代码,都能在脑中想象出编译后的模样,指令如何执行,内存如何分配,等等。而 C 的复杂在于,它有太多隐晦而不着边际的规则,着实让人头疼。相比较而言,Go 从零开始,没有历史包袱,在汲取众多经验教训后,可从头规划一个规则严谨、条理简单的世界。

Go语言的语法规则严谨,没有歧义,更没什么黑魔法变异用法。任何人写出的代码都基本一致,这使得Go语言简单易学。放弃部分“灵活”和“自由”,换来更好的维护性,我觉得是值得的。

将“++”、“–”从运算符降级为语句,保留指针,但默认阻止指针运算,带来的好处是显而易见的。还有,将切片和字典作为内置类型,从运行时的层面进行优化,这也算是一种“简单”。

并发模型

时至今日,并发编程已成为程序员的基本技能,在各个技术社区都能看到诸多与之相关的讨论主题。在这种情况下Go语言却一反常态做了件极大胆的事,从根本上将一切都并发化,运行时用 Goroutine 运行所有的一切,包括 main.main 入口函数。

可以说,Goroutine 是 Go 最显著的特征。它用类协程的方式来处理并发单元,却又在运行时层面做了更深度的优化处理。这使得语法上的并发编程变得极为容易,无须处理回调,无须关注线程切换,仅一个关键字,简单而自然。

搭配 channel,实现 CSP 模型。将并发单元间的数据耦合拆解开来,各司其职,这对所有纠结于内存共享、锁粒度的开发人员都是一个可期盼的解脱。若说有所不足,那就是应该有个更大的计划,将通信从进程内拓展到进程外,实现真正意义上的分布式。

内存分配

将一切并发化固然是好,但带来的问题同样很多。如何实现高并发下的内存分配和管理就是个难题。好在 Go 选择了 tcmalloc,它本就是为并发而设计的高性能内存分配组件。

可以说,内存分配器是运行时三大组件里变化最少的部分。刨去因配合垃圾回收器而修改的内容,内存分配器完整保留了 tcmalloc 的原始架构。使用 cache 为当前执行线程提供无锁分配,多个 central 在不同线程间平衡内存单元复用。在更高层次里,heap 则管理着大块内存,用以切分成不同等级的复用内存块。快速分配和二级内存平衡机制,让内存分配器能优秀地完成高压力下的内存管理任务。

在最近几个版本中,编译器优化卓有成效。它会竭力将对象分配在栈上,以降低垃圾回收压力,减少管理消耗,提升执行性能。可以说,除偶尔因性能问题而被迫采用对象池和自主内存管理外,我们基本无须参与内存管理操作。

垃圾回收

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

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

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

静态链接

Go 刚发布时,静态链接被当作优点宣传。只须编译后的一个可执行文件,无须附加任何东西就能部署。这似乎很不错,只是后来风气变了。连着几个版本,编译器都在完善动态库 buildmode 功能,场面一时变得有些尴尬。

暂不说未完工的 buildmode 模式,静态编译的好处显而易见。将运行时、依赖库直接打包到可执行文件内部,简化了部署和发布操作,无须事先安装运行环境和下载诸多第三方库。这种简单方式对于编写系统软件有着极大好处,因为库依赖一直都是个麻烦。

标准库

功能完善、质量可靠的标准库为编程语言提供了充足动力。在不借助第三方扩展的情况下,就可完成大部分基础功能开发,这大大降低了学习和使用成本。最关键的是,标准库有升级和修复保障,还能从运行时获得深层次优化的便利,这是第三方库所不具备的。

Go 标准库虽称不得完全覆盖,但也算极为丰富。其中值得称道的是 net/http,仅须简单几条语句就能实现一个高性能 Web Server,这从来都是宣传的亮点。更何况大批基于此的优秀第三方 Framework 更是将 Go 推到 Web/Microservice 开发标准之一的位置。

当然,优秀第三方资源也是语言生态圈的重要组成部分。近年来崛起的几门语言中,Go 算是独树一帜,大批优秀作品频繁涌现,这也给我们学习 Go 提供了很好的参照。

工具链

完整的工具链对于日常开发极为重要。Go 在此做得相当不错,无论是编译、格式化、错误检查、帮助文档,还是第三方包下载、更新都有对应的工具。其功能未必完善,但起码算得上简单易用。

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

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

三. 优秀项目

1) Docker

Docker 是一种操作系统层面的虚拟化技术,可以在操作系统和应用程序之间进行隔离,也可以称之为容器。Docker 可以在一台物理服务器上快速运行一个或多个实例。例如,启动一个 CentOS 操作系统,并在其内部命令行执行指令后结束,整个过程就像自己在操作系统一样高效。

项目链接:https://github.com/docker/docker

2) Go语言

Go语言自己的早期源码使用C语言和汇编语言](http://c.biancheng.net/asm/)写成。从) 写成,从Go 1.5 版本后,完全使用Go语言自身进行编写。Go语言的源码对了解Go语言的底层调度有极大的参考意义,建议希望对Go语言有深入了解的读者读一读。

项目链接:https://github.com/golang/go

3) Kubernetes

Google 公司开发的构建于 Docker 之上的容器调度服务,用户可以通过 Kubernetes 集群进行云端容器集群管理。系统会自动选取合适的工作节点来执行具体的容器集群调度处理工作。其核心概念是 Container Pod(容器仓)。

项目链接:https://github.com/kubernetes/kubernetes

4) etcd

一款分布式、可靠的 KV 存储系统,可以快速进行云配置。由 CoreOS 开发并维护键值存储系统,它使用Go语言编写,并通过 Raft 一致性算法处理日志复制以保证强一致性。

项目链接:https://github.com/coreos/etcd

5) beego

beego 是一个类似 Python 的 Tornado 框架,采用了 RESTFul 的设计思路,使用Go语言编写的一个极轻量级、高可伸缩性和高性能的 Web 应用框架。

项目链接:https://github.com/astaxie/beego

6) martini

一款快速构建模块化的 Web 应用的Go语言框架。

项目链接:https://github.com/go-martini/martini

7) codis

国产的优秀分布式 Redis 解决方案。可以将 codis 理解成为 Web 服务领域的 Nginx,它实现了对 Redis 的反向代理和负载均衡。

项目链接:https://github.com/CodisLabs/codis

8) delve

Go语言强大的调试器,被很多集成环境和编辑器整合。

项目链接:https://github.com/derekparker/delve

四. 使用Go的巨头

1) Google

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

2) Facebook

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

3) 腾讯

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

4) 百度

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

5) 七牛云

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

6) 京东

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

7) 小米

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

8) 360

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

除了上面提到的,还有很多公司开始尝试使用Go语言,比如美团、滴滴、新浪等。Go语言的强项在于它适合用来开发网络并发方面的服务,比如消息推送、监控、容器等,所以在高并发的项目上大多数公司会优先选择 Golang 作为开发语言

五. Go语言适用场景

服务器编程

以前你如果使用C或者C++做的那些事情,用Go来做很合适,例如处理日志、数据打包、虚拟机处理、文件系统等。

分布式系统

数据库代理器等

网络编程

这一块目前应用最广,包括Web应用、API应用、下载应用

内存数据库

前一段时间google开发的groupcache,couchbase的部分组建

云平台

目前国外很多云平台在采用Go开发,CloudFoundy的部分组建,前VMare的技术总监自己出来搞的apcera云平台。

六. Go标准库

在Go语言的安装文件里包含了一些可以直接使用的包,即标准库。Go语言的标准库(通常被称为语言自带的电池),提供了清晰的构建模块和公共接口,包含 I/O 操作、文本处理、图像、密码学、网络和分布式应用程序等,并支持许多标准化的文件格式和编解码协议

Go语言的编译器也是标准库的一部分,通过词法器扫描源码,使用语法树获得源码逻辑分支等。Go语言的周边工具也是建立在这些标准库上。在标准库上可以完成几乎大部分的需求。

在 Windows 下,标准库的位置在Go语言根目录下的子目录 pkg\windows_amd64 中;

在 Linux 下,标准库在Go语言根目录下的子目录 pkg\linux_amd64 中(如果是安装的是 32 位,则在 linux_386 目录中)。

一般情况下,标准包会存放在 $GOROOT/pkg/$GOOS_$GOARCH/ 目录下

Go语言标准库中常见的包及其功能

Go语言标准库包名 功 能
bufio 带缓冲的 I/O 操作
bytes 实现字节操作
container 封装堆、列表和环形列表等容器
crypto 加密算法
database 数据库驱动和接口
debug 各种调试文件格式访问及调试功能
encoding 常见算法如 JSON、XML、Base64 等
flag 命令行解析
fmt 格式化操作
go Go语言的词法、语法树、类型等。可通过这个包进行代码信息提取和修改
html HTML 转义及模板系统
image 常见图形格式的访问及生成
io 实现 I/O 原始访问接口及访问封装
math 数学库
net 网络库,支持 Socket、HTTP、邮件、RPC、SMTP 等
os 操作系统平台不依赖平台操作封装
path 兼容各操作系统的路径操作实用函数
plugin Go 1.7 加入的插件系统。支持将代码编译为插件,按需加载
reflect 语言反射支持。可以动态获得代码中的类型信息,获取和修改变量的值
regexp 正则表达式封装
runtime 运行时接口
sort 排序接口
strings 字符串转换、解析及实用函数
time 时间接口
text 文本模板及 Token 词法器

七.安装配置

下载地址:

https://studygolang.com/

https://golang.google.cn/dl/

Go 的环境变量

GOROOT:值为 Go 语言的当前安装目录。

GOPATH:值为 Go 语言的工作区的集合(可以有很多个)。

工作区类似于工作目录。每个不同的目录之间用:分隔。(不同操作系统,GOPATH 列表分隔符不同,UNIX-like 使用 :冒号,Windows 使用;分号

安装

windows

可以下载对应的zip包或者msi安装程序。如果电脑是 32 位系统的话,则需要下载 32 位的开发包

注意:通过下载zip的方式需要自己配置环境变量

  • GOROOT表示Go语言库的根目录的完整路径
  • GOPATH 可以先不配置,在做项目时需要配置,表示项目路径
  • PATH 环境变量中配置内容 %GOROOT%\bin , 方便在命令行快速调用Go语言库中工具

打开cmd运行go version说明安装配置成功

Linux安装

下载

1
wget https://golang.google.cn/dl/go1.15.5.linux-amd64.tar.gz

解压

1
tar -C /usr/local -xzf go1.15.5.linux-amd64.tar.gz

解压成功后会在当前目录下新增一个 go 目录,至此我们的Go语言开发包就安装完成了,使用cd命令进入该目录,然后执行bin/go version命令就可以查看当前Go语言的版本了

1
cd go bin/go version

配置环境变量

需要配置 2 个环境变量分别是 GOROOT 和 PATH。

  • GOROOT 的值应该为Go语言的当前安装目录:export GOROOT=/usr/local/go
  • PATH 为了方便使用Go语言命令和 Go 程序的可执行文件,需要追加其值:export PATH=$PATH:$GOROOT/bin:$GOBIN
1
2
3
4
5
6
vim /etc/profile 
# 以下内容添加到文件末尾
export GOROOT=/usr/local/go
export PATH=$PATH:$GOROOT/bin
#保存退出 使配置生效
source /etc/profile

目录介绍

目录名 说明
api 每个版本的 api 变更差异
bin go 源码包编译出的编译器(go)、文档工具(godoc)、格式化工具(gofmt)
doc 英文版的 Go 文档
lib 引用的一些库文件
misc 杂项用途的文件,例如 Android 平台的编译、git 的提交钩子等
pkg Windows 平台编译好的中间文件
src 标准库的源码
test 测试用例

八. 知识图谱