犹记得2019年中旬进行知识点的学习和demo的练习,熟悉各种语法和并发调度的场景,
在2019年末开始参与项目实战开发和逻辑梳理
Go语言的接触也是更多探索和业务的拆件,做一些雏形工具,来慢慢的孵化业务生态
后来陆陆续续,在主营业务是PHP的情况下,尽量在业务脚本的倾向上使用Go语言,虽然前期两种语言的混合使用,总会导致写法冲突,但好在这个磨合期平稳度过。
后来也会将公司更多的业务倾向于Go来进行处理,比如新项目,或者老项目对并发要求高的项目会优先考虑。
罗列下Go语言的特点:
Go主要有静态语言、天生并发、内置GC、安全性高、语法简单、交叉编译和编译快速这几个方面的特性。
这些特性决定了Go的三个高富帅特性:运行快、开发快和部署快,而这些特性都是针对Google遇到的一些痛点来设计的。
优势
- Go天生的自带并发调度,如协程和通道,且协程内存占用少,一个Goroutine栈空间最小2K
- Go自带的格式统一,gofmt工具
- Go语法的简洁,可读性强,严格语言规范
- Go作为静态语言,编译效率高,性能相对高
- Go跨平台的编译使用,跟操作shell命令一样的调用,部署方便,目前很多脚本都是这么来做的。
- 丰富的内置类型,内置强大的工具
- 内置runtime,自动垃圾回收机制
不足
- 错误处理,会有错误难获取
- 基于github获取代码库,会存在有代码库下架问题
Go适合做什么
- 服务器编程,如:处理日志,数据打包,虚拟机处理,文件系统
- 分布式系统,数据库代理器
- 网络编程,如:Web应用、API应用、下载应用
- 内存数据库
- 云平台,Docker,Kubernetes等应用开发
GO语言的关键特性主要包括以下几方面:
- 并发与协程
- 基于消息传递的通信方式
- 丰富实用的内置数据类型
- 函数多返回值
- defer机制
- 反射(reflect)
- 高性能HTTP Server
- 工程管理
- 编程规范
Go成功的项目
- Go成功的项目nsq:bitly开源的消息队列系统,性能非常高,目前他们每天处理数十亿条的消息
- docker:基于lxc的一个虚拟打包工具,能够实现PAAS平台的组建。
- packer:用来生成不同平台的镜像文件,例如VM、vbox、AWS等,作者是vagrant的作者
- skynet:分布式调度框架
- Doozer:分布式同步工具,类似ZooKeeper
- Heka:mazila开源的日志处理系统
- cbfs:couchbase开源的分布式文件系统
- tsuru:开源的PAAS平台,和SAE实现的功能一模一样
- groupcache:memcahe作者写的用于Google下载系统的缓存系统
- god:类似redis的缓存系统,但是支持分布式和扩展性
- gor:网络流量抓包和重放工具
码云上项目
- 1、项目名称:基于 Go 实现的高性能代理服务器,项目地址:https://gitee.com/snail/proxy
- 2、项目名称:基于 Go 实现的 Git 服务,项目地址:https://gitee.com/Unknown/gogs
- 3、项目名称:基于 Go 开发的开源文库系统,项目地址:https://gitee.com/truthhun/DocHub
- 4、项目名称:基于 Go 实现的内网穿透 ,项目地址:https://gitee.com/wapai/chuantou
- 5、项目名称:基于 Go 实现的 Web 开发框架,项目地址:https://gitee.com/johng/gf
- 6、项目名称:基于 Go 实现的高性能爬虫,基于go_spider开发
接下来介绍下关于Go的并发相关的内容
Go 调度器实现机制
Go 调度器模型我们通常叫做G-P-M 模型,他包括 4 个重要结构,分别是G、P、M、Sched:
G:Goroutine,每个 Goroutine 对应一个 G 结构体,G 存储 Goroutine 的运行堆栈、状态以及任务函数,可重用。
G 并非执行体,每个 G 需要绑定到 P 才能被调度执行。
P: Processor,表示逻辑处理器,对 G 来说,P 相当于 CPU 核,G 只有绑定到 P 才能被调度。
对 M 来说,P 提供了相关的执行环境(Context),如内存分配状态(mcache),任务队列(G)等。
P 的数量决定了系统内最大可并行的 G 的数量(前提:物理 CPU 核数 >= P 的数量)。
P 的数量由用户设置的 GoMAXPROCS 决定,但是不论 GoMAXPROCS 设置为多大,P 的数量最大为 256。
M: Machine,OS 内核线程抽象,代表着真正执行计算的资源,在绑定有效的 P 后,进入 schedule 循环;
而 schedule 循环的机制大致是从 Global 队列、P 的 Local 队列以及 wait 队列中获取。
M 的数量是不定的,由 Go Runtime 调整,为了防止创建过多 OS 线程导致系统调度不过来,目前默认最大限制为 10000 个。
M 并不保留 G 状态,这是 G 可以跨 M 调度的基础。
Sched:Go 调度器,它维护有存储 M 和 G 的队列以及调度器的一些状态信息等。
调度器循环的机制大致是从各种队列、P 的本地队列中获取 G,切换到 G 的执行栈上并执行 G 的函数,调用 Goexit 做清理工作并回到 M,如此反复。