服务器语言-go语言特点详解

幸运草 2020年4月12日21:14:25前端框架评论阅读模式

“ 通过简单的总结与介绍,带领大家去解开Go语言的神秘面纱。”

 

01 —为什么选择Go

1.1 诞生

    Go语言诞生于2007年的谷歌,作为谷歌IT工程师的兼职项目,利用20%的空闲时间参与Go语言的研发。创始人三位:罗伯特·格瑞史莫(Robert Griesemer) 、罗勃特·派克(Rob Pike) 和肯尼斯·汤普逊(Ken Thompson) 。吉祥物由Rob Pike手绘出来的,吉祥物的进化史,总之就是很可爱很萌的土拨鼠,也有人说是囊地鼠。 

1.2 Why Go

    从诞生之际,Go的出生就是为了取代C++,Go目前的执行性能、近解析型语言的开发效率以及近乎完美的编译速度,已经越来越备受程序员的喜爱。Go1.5解决了对C语言的依赖,完全移除了C语言部分,使用Go编译Go。并对GC进行重新设计,支持并发GC,解决GC时延问题。在Go1.8时,GC延时已经可以控制在1ms内,可以说在服务器端开发上,Go近乎完美,抹平了所有弱点。

 

 

 

 

02

语言特点

 

 

2.1 弱化版的指针

    C++中的指针,在指针运算、偏移、转换等相较复杂,同时内存释放也极不方便。

    Go语言中的指针,可以被拆分成一下两个核心概念:

  • 类型指针。允许对这个指针类型的数据,传递数据使用指针,无须拷贝数据。强制规定类型指针不能进行偏移和运算。

  • 切片。由指向起始元素的原始指针、元素数量和容量组成。

    对比两者,Go语言既拥有高效的数据访问能力,又不会发生指针偏移。避免修改关键性数据。最重要的是可以自动进行内存的垃圾回收。

 

2.2 引入包

    Go的包管理一直被人诟病,经过多种工具的演变,从go vendor,到godep,再到dep。包主要用于组织程序结构,Go语言的一个文件都要归属于一个包,不能单独存在。

    使用方法:

  • 初始化。在已有的项目目录中,使用go mod init <包名>初始化。包名通常类似github.com/golang/dep这种格式。如果包内有自引用,则包名需要和包内自引用名相同,才能正常导入。这时项目中生成一个go.mod文件。

  • 编译运行。直接执行go build/run,会发现项目涉及的包被自动安装了。这时项目中新增go.sum文件。原来的go.mod中增加了依赖项。

 

2.3 自动垃圾回收

    Go语言编译器会自动决定把一个变量放在栈还是放在堆,编译器会做逃逸分析(escape analysis),当发现变量的作用域没有跑出函数范围,就可以在栈上,反之则必须分配在堆。所以不用担心会不会导致memory leak,因为Go语言有强大的垃圾回收机制。go语言声称这样可以释放程序员关于内存的使用限制,更多的让程序员关注于程序功能逻辑本身。

    Go采用三色标记和写屏障,这是个并发的标记算法。

  • 起初所有的对象都是白色。

  • 扫描找出所有可达对象,标记为灰色,放入待处理队列。

  • 从队列中提取灰色对象,将其引用对象标记为灰色放入队列。

  • 写屏障监视对象的内存修改,重新标色或放回队列。

 

 

2.4 天然支持并发(非常重要)

  • 从语言层面支持并发,实现简单,一般与管道结合使用

  • Goroutine,轻量级线程,可实现大并发处理,高效利用多核

  • 给予CPS并发模型(Communicating Sequential Processes)实现 

 

2.5 管道通信机制

 

    Channels 允许 go routines 之间相互通信。你可以把 channel 看作管道,goroutines 可以往里面发消息,也可以从中接收其它 go routines 的消息。Goroutines 可以往 channel 发送消息,也可以从中接收消息。这是通过箭头操作符 (<-) 完成的,它指示 channel 中的数据流向。

    Channels也分为两种:

  • Unbuffered channels,它的特点在于每次只有一份数据可以通过。

  • Buffered channels,可以指定容量,允许发送多份数据。 

 

2.6 多个返回值

    Go语言在静态开发语言中率先提供了多返回值得功能。可以让开发者从原来各种比较别扭的方式返回多个值得痛苦中解脱,既不用区分参数列表中哪几个用于输入,哪几个用于输出,也不用再只为返回多个值而专门定义一个数据结构。

 

2.7 新的创新,延迟执行defer等

    Go语言中提供很多关键字,其中defer用于延迟一个函数或者方法的执行,它只能出现在函数或者方法的内部,经常用于处理成对的操作,如打开、关闭、连接、断开连接,枷锁、释放锁等。

    通过defer机制,不管函数逻辑多复杂,都能保证在任何执行路径下,资源被释放。如果一个函数中有多个defer语句,它们都会以LIFO后进先出的顺序执行。即使某个函数繁盛调用错误,调用依旧会被执行。

 

 

 

03语言优势

 

3.1 性能

    通过对 C(gcc)、C++、Java、JavaScript 和 Go语言的测试。性能比较如下表所示,表中数据的单位为秒,数值越小表明运行性能越好。

 

编程语言↓ / 测试用例→

reverse-complement

pidigits

fannkuch-redux

fasta

spectral-norm

C语言

0.42

1.73

8.97

1.33

1.99

C++

0.6

1.89

10.35

1.48

1.99

Go

0.49

2.02

14.49

2.17

3.96

Java

1.13

3.12

15.09

2.32

4.25

JavaScript

4.3

N/A

81.49

9.79

16.17 

    通过上表可以看出,Go语言在性能上更接近于 Java 语言,虽然在某些测试用例上不如经过多年优化的 Java 语言,但毕竟 Java 语言已经经历了多年的积累和优化。Go语言在未来的版本中会通过不断的版本优化提高单核运行性能。 

 

3.2 开发效率

    并行和异步编程几乎无痛点。Go 语言的 Goroutine 和 Channel 这两个神器简直就是并发和异步编程的巨大福音。像 C、C++、Java、Python 和 JavaScript 这些语言的并发和异步方式太控制就比较复杂了,而且容易出错,而 Go 解决这个问题非常地优雅和流畅。这对于编程多年受尽并发和异步折磨的编程者来说,完全就是让人眼前一亮的感觉。Go 是一种非常高效的语言,高度支持并发性。Go是为大数据、微服务、并发而生的一种编程语言。

 

3.3 并发性&通道

    Go致力于将编程简单化,它并未引入很多新概念,而是聚焦于打造一门简单的语言,它使用起来异常快速并且简单。其唯一的创新之处是 goroutines 和通道。Goroutines 是 Go 面向线程的轻量级方法,而通道是 goroutines 之间通信的优先方式。创建 Goroutines 的成本很低,只需几千个字节的额外内存,正由于此,才使得同时运行数百个甚至数千个 goroutines 成为可能。你可以借助通道实现 goroutines 之间的通信。Go 运行时间可以表示所有的复杂性。Goroutines 以及基于通道的并发性方法使其非常容易使用所有可用的 CPU 内核,并处理并发的 IO——所有不带有复杂的开发。相较于 Python/Java,在一个 goroutine 上运行一个函数需要最小的样板代码。

 

3.4 编译速度

    当前我们使用 Go 编写的最大微服务的编译时间只需 6 秒。相较于 Java 和 C++呆滞的编译速度,Go 的快速编译时间是一个主要的效率优势。我热爱击剑,但是当我依然记得代码应该做什么之时,事情已经完成就更好了。

 

3.5 强大的生态系统

    对我们这么大小的团队(大约 20 人)而言,生态系统很重要。如果你需要重做每块功能,那就无法为客户创造收益了。Go 有着强大的工具支持,面向 Redis、RabbitMQ、PostgreSQL、Template parsing、Task scheduling、Expression parsing 和 RocksDB 的稳定的库。

    Go 的生态系统相比于 Rust、Elixir 这样的语言有很大的优势。当然,它又略逊于 Java、Python 或 Node 这样的语言,但它很稳定,而且你会发现在很多基础需求上,已经有高质量的文件包可用了。

 

3.6 支持gRPC和Protocol Buffers

    Go 语言对 protocol buffers 和 gRPC 有一流的支持。这两个工具能一起友好地工作以构建需要通过 RPC 进行通信的微服务器(microservices)。我们只需要写一个清单(manifest)就能定义 RPC 调用发生的情况和参数,然后从该清单将自动生成服务器和客户端代码。这样产生代码不仅快速,同时网络占用也非常少。

 

 

 

04语言优势

 

4.1 缺少框架

    相较Python、Java等语言,Go语言没有一个主要的框架。这是 Go 语言社区激烈讨论的问题,因为许多人认为我们不应该从使用框架开始。在很多案例情况中确实如此,但如果只是希望构建一个简单的 CRUD API,那么使用 Django/DJRF、Rails Laravel 或 Phoenix 将简单地多。

 

4.2 错误处理   

    在Go语言中,错误返回的都是值,大部分函数最后会返回error。因此在函数调用后需要用代码进行判空处理,而不像Java语言中使用try-catch机制,error不会使程序崩溃。

    Go的panic包含了堆栈跟踪,但是error没有,极不方便调试,因此获取上下文信息方面稍有难度,导致很难提供有意义的错误信息。错误包(errors package)可以允许我们添加返回错误的上下文和堆栈追踪而解决该问题。

 

4.3 包管理

     Go 语言的软件包管理绝对不是完美的。默认情况下,它没有办法制定特定版本的依赖库,也无法创建可复写的 builds。相比之下 Python、Node 和 Ruby 都有更好的软件包管理系统。然而通过正确的工具,Go 语言的软件包管理也可以表现得不错。

    我们可以使用 Dep 来管理依赖项,它也能指定特定的软件包版本。除此之外,我们还可以使用一个名为 VirtualGo 的开源工具,它能轻松地管理 Go 语言编写的多个项目。

 

 

 

05总结

 

    Go语言主要用作服务器端开发,其定位是用来开发“大型软件”的,适合于很多程序员一起开发大型软件,并且开发周期长,支持云计算的网络服务。Go语言能够让程序员快速开发,并且在软件不断的增长过程中,它能让程序员更容易地进行维护和修改。它融合了传统编译型语言的高效性和脚本语言的易用性和富于表达性。

    Go语言作为服务器编程语言,很适合处理日志、数据打包、虚拟机处理、文件系统、分布式系统、数据库代理等;网络编程方面,Go语言广泛应用于Web应用、API应用、下载应用等;除此之外,Go语言还可用于内存数据库和云平台领域,目前国外很多云平台都是采用Go开发。

 

特别声明:以上文章内容仅代表作者本人观点,不代表变化吧观点或立场。如有关于作品内容、版权或其它问题请于作品发表后的30日内与变化吧联系。

  • 赞助本站
  • 微信扫一扫
  • weinxin
  • 加入Q群
  • QQ扫一扫
  • weinxin
幸运草
Go语言接口规则 前端框架

Go语言接口规则

Go语言接口规则 接口是一个或多个方法签名的集合。任何类型的方法集中只要拥有该接口对应的全部方法签名。就表示它 "实现" 了该接口,无须在该类型上显式声明实现了哪个接口。对应方法,是指有相同名称、参数...
Go语言中处理 HTTP 服务器 前端框架

Go语言中处理 HTTP 服务器

1 概述 包 net/http 提供了HTTP服务器端和客户端的实现。本文说明关于服务器端的部分。 快速开始: package main import (   "log"   "net/http" )...

发表评论