Go与C/C++消耗的CPU差距不大,但由于Go是垃圾回收型语言,耗费的内存会多一些。 拿Go与同为垃圾回收型语言的Java简单比较一下。
Java当年诞生时最大的卖点之一是“一次编写,到处运行”。这个特性在20年前很棒,因为市场上几乎没有虚拟化解决方案。但是到了今天出现了Docker之类一系列跨平台工具,这种卖点可能被看做一种短板,主要原因如下:
抛去JVM启动和预热时间,运行一个最简单的HTTP程序,与Go对比,Java在CPU上的消耗多约20%,内存上的消耗约高两个数量级。
开发过网络库的同学可能都知道Unix的epoll
调用,如果了解Windows应该听说过IOCP
,这两种接口分别对应网络的Reactor和Proactor
模式。
简单来说,前者是同步的事件驱动模型,后者是异步IO。不论使用任何语言只要涉及到高性能并发IO都逃不过这两种模式开发的折磨——除了Go
。
一般来说一个服务进程包含main、日志、网络、其他外部依赖库线程,以及核心的服务处理(计算)线程,其中服务线程可能会按CPU核数配置开启多个。
go创建的goroutine
相当于将IO读写和事件触发拼接起来的一个容器,消耗的内存非常小,所有goroutine
被Go自动调度到有限个数的线程中,运行中切换基本是使用epoll
的事件机制,因此这种协程机制可以很迅速启动成千上万个而不太消耗性能。
Go作为工程语言而设计,即使一个团队有多种风格的开发者,他们的流程和产出最终都需要尽量保持一致,这样协同开发效率才会高。为了保证各方面的统一,Go提供了多种工具,安装以后执行go命令就能直接使用。
go run:直接运行go代码文件
go build:编译到本目录
go install:编译并安装到统一目录,比build快
go fmt:格式化代码,写完代码一定要记得用
go get:下载并安装包和依赖库
go mod:包管理,1.11版加入
go test:运行单元测试
go doc:将代码注释输出成文档
go tool:实用工具集,包括静态错误检查、测试覆盖率、性能分析、生成汇编等等
Go是一种适应分布式系统和云服务的语言,所以它直接将静态编译作为默认选项,也就是说编译之后只要将可执行文件扔到服务器上或者容器里就能没有任何延迟地运行起来,不需要任何外部依赖库。 Go的项目只要在编译时修改参数,就能交叉编译出其他任意支持平台所需的二进制文件。比如在macOS上开发,当需要在linux服务器上测试则使用如下命令编译:
GOOS=linux GOARCH=amd64 go build ./...