导语
Go语言(也称为Golang)是google在2009年推出的一种编译型编程语言。相对于大多数语言,golang具有编写并发或网络交互简单、丰富的数据类型、编译快等特点,比较适合于高性能、高并发场景。本文主要基于笔者的亲身实践和总结,介绍golang的一些特性,重点介绍并发的实现和使用,希望能引发读者一些启发或兴趣。
1、Golang简介
Go语言(也称为Golang)是google在2009年推出的一种编译型编程语言。相对于大多数语言,golang具有编写并发或网络交互简单、丰富的数据类型、编译快等特点,比较适合于高性能、高并发场景。2015年度的TIOBE指数计算机语言份额排名中,golang排在60+名,19年7月已上升到16名。
笔者曾于15年上半年在2个实际项目中引入golang 1.3,代码量大概在3000行左右,最大的体会是并发编程入门容易。本文将以1.3来介绍,不过golang团队更新太快,19年最新版本已到了1.12,不过核心设计思想与1.3并无大差异。
众所周知,曾经在很长一段时间里,google保持着一个传统,允许员工拥有20%自由时间来开发实验性项目,可惜现在该制度已经废弃。golang正是由一个强大团队利用这20%时间开发的。这里有必要介绍一下该团队的核心成员,个个来头不小,都是计算机领域大神级人物。最大牌的当属B和C语言设计者、Unix和Plan 9创始人、1983年图灵奖获得者Ken Thompson,其以70+岁高龄,不知道在golang实际开发中撰了多少代码......另外,这份名单中还包括了Unix核心成员Rob Pike、java HotSpot虚拟机和js v8引擎的开发者Robert Griesemer、Memcached作者Brad Fitzpatrick,等等。
OK,进入正题,笔者结合个人整理和思考,依次介绍golang几个值得一说的特性和精髓,如果读者能从中受到某些启发,就足够了。
2、并发编程
通过实践,笔者认为golang在并发编程方面比绝大多数语言要简洁不少,这一点是其最大亮点之一,也是其在未来进入高并发高性能场景的重要筹码。
不同于传统的多进程或多线程,golang的并发执行单元是一种称为goroutine的协程。协程这个概念已被引入到不少语言中,比如golang、python、lua等。协程经常被理解为轻量级线程,一个线程可以包含多个协程,共享堆不共享栈。协程间一般由应用程序显式实现调度,上下文切换无需下到内核层,高效不少。协程间一般不做同步通讯,而golang中实现协程间通讯有两种:1)共享内存型,即使用全局变量+mutex锁来实现数据共享;2)消息传递型,即使用一种独有的channel机制进行异步通讯。
由于在共享数据场景中会用到锁,再加上GC,其并发性能有时不如异步复用IO模型,因此相对于大多数语言来说,golang的并发编程简单比并发性能更具卖点。
2.1、示例说明
下面是一段用golang写的并发程序:
package main
import {
"fmt"
"runtime"
"time"
}
var MULTICORE int
func main() {
MULTICORE = runtime.NumCPU() //计算出本地的cpu核总数
//指定MULTICORE个核来运行
//这里没有设置cpu亲和性,所以各个线程会在任意cpu核上跑,同一个线程也可能会不断跳到不同核上运行
runtime.GOMAXPROCS(MULTICORE)
// 启动MULTICORE个goroutine来执行test()
for i := 0; i < MULTICORE; i++ {
go test()
}
// sleep 10s是为了让主进程等待所有goroutine都运行退出
time.Sleep(10*time.Second)
}
func test() {
for i := 0; i < 10; i++ {
fmt.Printf("test\n")
}
}
可以看出,启动一个goroutine很容易,只需要在(匿名)函数前面加个go关键字就行,还能够指定运行核数,以期充分利用机器的计算能力。
2.2、底层实现
golang相较于传统语言,为了更好适应现代多核、高并发场景,独创了自己的协程模型,采用m:n模型,即m个gorountine(简称为G)映射到n个用户态上下文(简称为P)上,一个P向上维护多个G组成的一个队列,一个P向下与一个内核态工作线程(简称为M)相绑定。
完整文章见:https://github.com/star2478/golang-wiki/wiki/%E6%B5%85%E8%B0%88Go%E8%AF%AD%E8%A8%80