Golang之美

3,780 阅读8分钟

初始golang,语言之美之简洁之高效,天生具有高并发等特性。 本文来自蔡欣圻、邵聪聪,对go语言的分析很到位全面,在这里分享出来给go开发者,希望能让你有一个更深刻的认知。

目录

  • Golang的哲学
  • Golang之美
  • Golang vs Java
  • 风靡世界?!
  • 我们的先行实践

Golang的哲学


1、go背景介绍: go语言是google 2009年发布的第二版开源编程语言,针对多处理器系统应用程序的编程进行了优化,使用Go编译的程序可以媲美C或C++代码的速度,而且更加安全、支持并行进程。

2、go是面向接口、组合编程;

3、正交性:语言设计的正交性,保证语言的稳定性和简单,go很好的遵循正交规律,如:goroutine接口、组合等;

4、少即是多:有且仅有一种方法把事情做好做对,保持简单行的方法是go语言特性紧提供一种方法,减少重复、冗余,把事情做到极致是go的原则;

5、并发语言层面支持:并发更好利用多核没有更强的表现力来模拟真实世界;

6、开放性:开源,语言的实现对程序员不是个黑盒子,任何想了解语言实现都可以参与。

7、强大的作者阵容:C语言之父、Unix系统之父、Utf8和javascript V8之父等等

Golang之美


一、 可直接编译成机器码,不依赖其他库,部署就是扔一个文件上去就完成了

二、 编译器和标准库、三方库都是Go语言实现,完全实现了语言上的自举,任何人都可以轻松根据自己的需求修改源代码,再也不用担心去阅读或者修改C或者C++实现的源码了

三、 静态类型语言,静态类型的语言就是可以在编译的时候检查出来隐藏的绝大多数问题

四、语言层面支持并发,这个就是Go最大的特色,天生的支持并发。天生的基因和整容是有区别的,大家一样美丽,但是你喜欢整容的还是天生基因的美丽呢?Go就是基因里面支持的并发,可以充分的利用多核,很容易的使用并发。

五、内置runtime、GC,从1.5开始GC已经逐渐趋于完美,下个版本1.8可以控制在海量存储对象的场景下,保证1ms内的gc耗时

六、简单易学,Go语言的作者都有C的基因,那么Go自然而然就有了C的基因,那么Go关键字是25个,但是表达能力很强大,几乎支持 大多数你在其他语言见过的特性:继承、多态、接口等。

七、丰富的标准库,Go目前已经内置了大量的库,特别是网络库非常强大,是目前标准库最强大的语言之一,基本上平时使用的所有功能都可以在标准库中觅得身影。

八、完善的第三方生态环境,你所需要的所有功能都可以在第三方库中找到,而且go的三方库开发非常活跃,这个通过github的统计数据就可以得知,具体的三方库部分列表可以通过awesome-go去查看

九、跨平台编译 可以在任何一个平台编译其它所有系统和平台的发布版本,例如在mac上编译windows、linux、plan9、fuchsia,编译平台包括i386、amd64、arm等等,所以go在物联网和嵌入式领域特别有优势,编译出来的不仅体积小,而且无需安装任何依赖就可以在嵌入式系统中运行

十、内嵌C、C++支持,前面说了作者是C的作者,所以Go里面也可以直接包含c代码,利用现有的丰富的C库,不过其实我们并不提倡这么做,因为Go语言已经足够快,也许只有在数据库底层存储这种场景需要调用C、C++函数去完成一些任务了。

十一、内置强大的工具 Go语言里面内置了很多标准工具链,包括了代码格式化和风格提示、单元测试、Benchmark、系统profile、代码生成、文档生成等等。

例如,gofmt工具,自动化格式化代码,能够让团队review变得如此的简单,代码格式一模一样,对于后续项目的维护非常有优势。很多人都发现go的第三方库的源码非常好阅读,就是因为简洁的语法和统一的代码风格。

下面附上Go自带的标准profile工具生成的图(在本地对远程的服务器进行profile),只需一行命令即可: 1、系统中各个函数的调用关系和CPU时间分布图:

go tool pprof -web http://xx.14.200:6001/debug/pprof/profile

2、内存使用大小分布:

go tool pprof -web -alloc_space http://xx.7.14.200:6001/debug/pprof/heap

3、内存对象分配数分布:

go tool pprof -web -alloc_objects http://xx.7.14.200:6001/debug/pprof/heap

4、强大、简单的benchmark

代码:


package bench
import (
	    "testing"
)
// 测试Xor性能
func BenchmarkXor(b *testing.B) {
	a := 0
	for i := 0; i < b.N; i++ {
		final := 0
		for i := 0; i < 1000; i++ {
			final ^= i
		}
		a = final
	}
	_ = a
}      

命令$: go test -v -run="none" -bench=. -benchmem -benchtime=‘3s’

结果 
BenchmarkXor-8   	20000000	       310 ns/op	       0 B/op	       0 allocs/op
PASS
ok  	go_test/bench	6.537s

Golang vs Java


1、面向对象比较:

一、 类型系统:

JAVA中有两套完全独立的类型系统,一套是值类型系统,byte、int、boolean、char、double另一套是以object类型为根的对象类型系统,Integer,HashMap等。值类型系统希望用object类型引用,则需要装箱。而go语言中多数类型都是原生的值类型(避免装箱可以节省大量的内存和CPU),甚至包括一些复合类型如数组(array),结构体(struct)等,并且这些类型都可以有方法。我们可以给任何类型增加新方法。同时Go语言可以通过&获得一个对象的引用如 var b=&a

二、内存排列:

Go因为没有类实例对象这种东东,因此Go的任何变量在内存中都是紧密连续排列的,对于内存的访问速度来说,亲和度是很高的,而且CPU缓存也更加容易命中。

三、成员的可访问性:

Java中使用private,protected,public,package等关键字进行访问控制。对于Go语言如果希望某个符号可被其他包(package)访问,需要将该符号定义为大写字母开头。小写字母开头的符号只能在包内访。

四、继承:

Java的继承通过extends关键字完成,不支持多继承。Go语言的继承通过匿名组合完成:基类以Struct的方式定义,子类只需要把基类作为成员放在子类的定义中,并且可以通过调整基类成员的位置改变内存布局(因此Go语言相对其它高级语言可以对内存实现很精细的控制,减少内存占用并提高性能)。

五、接口:

java中的接口作为不同组件中的契约存在,是强制的,类必须声明实现了某接口,需要从该接口继承。哪怕是两个一模一样的接口但只有名字不一样,也只能根据类所声明的实现接口是否包括该接口来决定该类是否实现该接口,叫做“侵入式”的接口。而GO语言中采用的是非侵入式接口,一个类只需要实现接口要求的所有函数,那我们就说该类型隐式实现了该接口,这个在使用第三方库的时候非常易用,大大减少了库之间的耦合度。GO语言可以通过接口进行接口查询(接口指向的对象是否实现了另外的接口),类型查询等

六、多态:

Java中的多态实现遵循一个原则:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。Java中的多态可以通过基于继承和基于接口两种方法实现。而在go语言一般不允许不同类型的赋值,即不支持传统的多态。interface是一个例外,可以用不同类型进行赋值只要一个类型实现了该接口,我们就可以将该类型的变量赋给该接口的变量。

2、多线程比较:

JAVA:

  1. JAVA 线程 与 OS 线程 1:1(其实这个是与虚拟机实现有关,下面说的都是1:1模式),所以调度由系统来决定的(抢占式)
  2. JAVA的线程可以设置Thread ID
  3. JAVA 的 栈是固定大小的
  4. JAVA 提供很多工具来调试(包括运行期)
  5. 相对来说开销要大很多
  6. new Thread(....).start();
  7. NIO性能很不错,但是使用和实现起来复杂很多很多

GOLANG:

  1. Goroutine 是用户态自己实现的线程,调度方式遇到IO/阻塞点方式就会让出cpu时间(其实也看编译器的实现,如果TA在代码里面插入一些yield,也是可以的。 反正现在不是抢占式的。)

  2. 不能设置goroutine ID, 也拿不到(可以调用C API或者自己修改源码暴漏出来,实际上修改起来挺简单的,因为Go的源码写的非常简洁优雅)

  3. goroutine的栈会自动扩容(初始stack很小,2KB,这也是go程序内存占用很小的原因) 4.相对java,多线程调试工具链有待完善,不过我们目前也没有发现需要这种调试的地方,实在需要时通过profile工具和简单的日志就可以( 目前有一些第三方的工具,不过因为并不需要,我们也没有使用过)

  4. 开销非常小,同时运行几百万个一点问题都没有

  5. go func(..) {} ()

  6. golang的最大特点就是这个goroutine非常简单方便,实现功能,都只要按照人类最直接的思维模式写就好(反正可以开大量的goroutine),不像回调的方式那么碎片化(nodejs),也远远不像NIO那么复杂(netty).一句话:可以用最简单的方式写出来非常高性能的并发

  • golang多线程例子:

mian.go // 启动海量子线程执行计算任务

package main
import (
	"log"
	"sync"
	"sync/atomic"
	"time"
)
var total int32 = 0
func main() {
	// 控制子线程的任务执行,等同于Map/Reduce处理
	wg := &sync.WaitGroup{}
	// 统计运行时间
	ts := time.Now()
	// 启动100万个线程,每个线程执行100次加1的任务,这里使用了锁,防止脏数据
             for i := 0; i < 1000000; i++ {
		// go标记的函数,自动在一个新的线程中去执行
		go func() {
		// 控制器的执行任务+1
                      wg.Add(1)
			// 子线程结束时,控制器的执行任务完成
			defer wg.Done()
			for i := 0; i < 100; i++ {
				atomic.AddInt32(&total, 1)
			}

		}()
	}
	
         // 这里主线程休眠一小短时间,防止子线程的任务控制wg.Add(1)还没有触发,主线程就执行完毕
	time.Sleep(1 * time.Millisecond)

	// 等待子线程的任务完成
	wg.Wait()

	// 输出最终运行时间
	log.Printf("启动100万个线程并执行计算任务完成,总计耗时:%v(毫秒)\n", time.Now().Sub(ts).Nanoseconds()/1000000)
	// 输出最终结果
	log.Println("最终计算结果为", total)
}

结果:
2018/11/21 14:43:04 启动100万个线程并执行计算任务完成,总计耗时:2022(毫秒)
2018/11/21 14:43:04 最终计算结果为 100000000

间隔运行$: go run main.go

间隔运行程序,会观察到CPU的变化情况,go高并发自动调用CPU核数来实现线程

3.Web比较

这个应该是两者区别最大的地方之一

Java: 使用Tomcat、jetty容器,或者使用netty中间件,也就是需要依赖第三方的东西

Golang: 只需要标准库就可以实现很高很高的性能,我们目前用的http和http2、https服务、websocket服务、tcp服务、静态文件服务器,在代码中都不会超过3行,非常非常简洁,因为使用的标准库,控制粒度非常细,可以说你就是自己代码的上帝

风靡世界?!


1、以下项目基本都是各自领域最火的项目之一,并且使用go作为最核心的语言

   CaaS : Docker , rkt等
   PaaS :  谷歌的k8s,flynn, deis等

2、云存储和存储服务:

  dropbox(2年时间估值300多亿美元),七牛云、乐视云

3、数据库:

  dgraph(谷歌的开源图数据库)、cockroach,codis, ,tidb,bolt,influxdb等

4、Api网关:

    Apple的网关、百度的BFE等等

5、监控平台:

    小米、滴滴、携程、360金融, influxdata(目前国外最后的开源系统监控解决方案),promethus

6、软负载均衡:

    谷歌的seesaw(替代lvs)

7、中间件:

   服务发现:etcd,,consul
   消息队列:nsq, nats 
   搜索: bleve(功能和ES一样,也是基于lucence技术)
   mysql代理:  vitess(youtube的mysql proxy,作用等同于mycat,撑起了youtube的所有mysql请求), kingshard(金山的mysql proxy)

8、安全平台:

  vault

9、CI(持续集成)平台:

  drone

10、Git web平台:

  gogs(我们公司内部在使用的git服务)

11、云计算虚拟网络vxlan层:

  flannel(性能是目前虚拟网络中最好的,跟物理网络性能几乎差不多),之前h3c说的云计算虚拟网络层的核心就是vxlan,只不过h3c是自己实现的

12、云计算基础服务:

  IBM的z system、阿里云的小部分服务,华为PaaS云(研究院在对k8s进行二次开发)、网易容器云、Cloud Foundry、UClound等等

13、云操作系统:

  coreos、plan9(这两个系统的kernel和部分非常底层的功能是用C语言实现,其它部分很多都是Go语言实现)

14、Saas云服务:

  这个很多也很杂,国外的创业公司居多

15、CDN:

  阿里、七牛、又拍云、dropbox等等

  • 直播平台和视频服务:阿里、bilibili、七牛、youtube、twitch、sex.com、facebook等等
  • 物联网(IoT):SpaceX(遥感器平台),gobot(机器人等IoT平台)、Canopy等等,可以说Go是目前做IoT开发的最流行的语言之一
  • 区块链技术: IBM的fabric,以太坊,比特币,国内的几个创业公司
  • 消息和聊天平台:360,bilibili等等,数不胜数
  • 新的传输层通信协议: ipfs
  • 机器学习: golearn、tensoflow(官方自带两种语言api:python和go)
  • 语音智能: 舜飞科技
  • VR: 爱奇艺正在秘密开发的VR平台
  • 网约车服务: 滴滴(新的巴士事业部使用go作为首选核心语言,旧的业务也在逐步用go重写)、uber(最核心也是并发最高的地图围栏算法服务,业务层面每秒并发15万以上,CPU和Web io双密集型服务)
  • Web服务: SoundCloud、google,有赞、微信电影票、百度等等
  • 金融业: 广发证券的实时行情分析系统是用Go重写的,在高峰期也能保证非常低、非常稳定的处理延迟,这个对于证券行业非常重要、平安金融的部份基础架构、银汇的Web服务。
  • 同时go还是游戏、dubo、色情等高并发行业的宠儿

我们的先行实践


1.消息推送和聊天平台:宙斯,数万行Go代码实现

2.通用Api网关

3.消息统计平台,为消息推送和聊天平台提供消息查询和统计服务,后面查询服务会通过ELK来做

4.分布式UUID服务

5.支付通知中心

6.Apns苹果推送

  1. 正在研发的开源监控平台Vgo(这个目前是利用业余时间私下在做的

我们的目标不仅仅是完成任务,更希望能通过开源打响传化走向技术市场的第一炮!