Go语言专题:为什么要学习Go

Posted 架构师之巅

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Go语言专题:为什么要学习Go相关的知识,希望对你有一定的参考价值。

为什么学习Go

在过去的几年里,有一种新的编程语言的热度在持续地上涨:Go或者叫Golang。唯一能让程序员疯狂的事,只有新出的编程语言了。

硬件限制

摩尔定律 正在失效。

2004年英特尔推出了第一款具有3.0GHz速度的Pentium 4处理器。今天,我的Macbook Pro 2016已经有了2.9GHz的速度。在这十年间,原生的处理速度并没有多大的进步。在下表中你可以看到这期间处理能力的对照情况。

Go语言专题(一):为什么要学习Go

从上图可以看出,单线程性能和处理器的频率在近十年内保持稳定。如果你认为增加更多的晶体管是解决方案,那么你就错了。这是因为在更小规模的情况下一些量子特性开始出现(如隧道),并且它实际上要投入更多的晶体管(为什么?),每美元增加晶体管的数量开始下降。

因此,对于上述问题的解决方案,

   · 制造商开始加入越来越多内核处理器。现在我们有四核和八核CPU可用。

   · 我们还推出了超线程技术。

   · 为处理器增加更多的缓存提高性能。

但是,上述的解决方案本身的局限性太大。我们不能通过为处理器添加越来越多的缓存来提高性能,因为缓存有物理极限:缓存越大,速度越慢。处理器增加更多内核也有其成本。此外,内核数量不能扩展到无限。这些多核处理器可以同时运行多个线程,并带来并发。我们将在后面讨论。

所以,如果我们不能依靠硬件的改进,提高性能的唯一办法就是更有效的软件。但可悲的是,现代的编程语言的效率都不太高。

现代处理器就像加满硝基燃料的汽车,它他们擅长的四分之一英里。不幸的是现代编程语言都像蒙特卡洛,他们充满曲折。“ — David Ungar


Go有协程!!

正如我们上面所讨论的,硬件厂商正在给处理器增加更多内核数量来提高性能。所有的数据中心都在这些处理器上运行,我们应该期待在未来几年核心数量能够增加。如今的应用更多地使用多个微服务维护的数据库连接,消息队列和维护缓存。因此,我们开发的软件和编程语言应该很支持并发,并且它们应该支持内核的数量的扩展。

但是,大多数现代编程语言(如Java,Python等)诞生于上世纪90年代的单线程环境,这些编程语言大多数支持多线程。但真正的问题是并发执行,线程锁,竞争条件和死锁。这些问题导致了很难用那些语言创建多线程应用程序。

举个例子,使用Java创建新的线程在内存上并不高效。每个线程占用的内存堆大小约为1MB,如果你开启数千个线程,就会让堆承受巨大的压力,将会由于内存不足导致关闭。另外,如果你想两个或多个线程之间进行通信,这是非常困难的。

另一方面,Go语言是在2009年发布的,此时多核心处理器已经可用。这就是为什么Go在语言层次上支持并发,Go有go协程而不是线程。他们消耗的堆内存几乎只有2KB。所以,你可以随时启动数百万的go协程。


其他的优点:

go协程有可增长的分段堆栈。这意味着,他们只在需要的时候才会使用更多的内存。

· go协程比线程启动更快。

· go协程配备了内置的原语,可以使它们(通道)之间的通信变得安全。

· go协程让你避免在共享数据结构时采取互斥锁。

· 此外,够程和OS线程不必1对1的映射。单个go协程可以在多个线程运行。go协程可以复用成少数OS线程。

以上各点,让Go可以像Java,C和C ++高效处理并发,同时像Earlang以简洁直观的代码执行并发。


Go直接在底层运行

使用C,C ++而不是其他现代高级语言如Java / Python中的一个最显着的好处是它们的性能,因为C / C ++编译型的而不是解释解释型的。

处理器对二进制友好。一般来说,当你建立一个使用Java或其他基于JVM的语言的程序,当你编译你的项目,它把人类可读的代码编译成JVM或于底层的操作系统上运行的其他虚拟机可以理解的字节码。执行期间,虚拟机解释那些字节码并将它们转换成可以被处理器理解的二进制文件。

另一方面,C / C ++不在虚拟机上执行并且去除这一层次以提高性能。编译器直接把人类可读代码编译成二进制文件。

然而,在这些语言中释放和分配变量是一个巨大的痛苦,尽管大多数编程语言使用垃圾收集器或引用计数算法来处理对象的分配和释放。

Go语言兼顾了这两个方面。Go像C / C ++等低级语言,是编译型语言。这意味着性能几乎接近低级语言。它还使用垃圾收集来分配和清除的对象。因此,没有更多的malloc()和free()语句!酷!!!

Go代码易于维护

让我告诉你一件事,Go没有其它语言一样疯狂的编程语法。它的语法非常整洁,干净。

Go语言的谷歌设计者在创造这门语言的时候已经想到了这个事情。随着谷歌有非常庞大的代码库和数以千计的开发人员正在处理相同的代码库,代码应该很简单让其他开发人员理解并且一个代码段应该对代码的另一段的副作用应当最小。这将使代码易于维护,易于修改。

Go故意遗漏了现代OOP语言的许多特性。

· 没有类。所有的事情仅划分成包。同时,Go用结构体替代了类。

· 不支持继承。这将使代码易于修改。像Java / Python语言,如果ABC类继承的XYZ类并且你改动了XYZ类,那么可能在继承了XYZ的其他类中产生一些副作用。通过删除继承,我们可以很容易地理解代码同时(因为当看一段代码时,不用当成超类来看待)

  ·没有构造函数.

   · 没有注解。

   · 没有泛型。

   · 没有exceptions(应该指的是像Java的错误类型)。

上述变化使Go与其他语言非常不同,也使使用Go语言编程不同于其他编程语言。你可能不喜欢上面的几点。但是,如果没有以上的几点特性,你不可能编写你的程序。你只需要做的是多写2-3行。好处是,它会使你的代码更加清晰。


Go是Google支持的

我知道这不是一个直接的技术优势。但是,很重要的一点是,Go是谷歌设计并支持的。谷歌拥有世界上最大的云基础设施之一,并且它的规模不断扩大。Go是由谷歌设计来解决他们的支持可扩展性和有效性问题。在创建自己的服务器,你将面临同样的问题。

· 即使Go不用于其他面向对象的语言,它仍然不可忽略。Go提供了像C / C ++一样的性能,像Java一样的超高效的并发处理,像Python / Perl一样有趣的代码。

  · 如果你没有任何计划去学习Go,我依旧认为硬件限制给了我们压力,从而软件开发人员可以编写出超级高效的代码。开发人员需要了解硬件,并对他们程序进行相应的优化。优化后的软件可以运行在更便宜和更慢的硬件上(如运行IOT设备)和最终用户的体验将得到更大的影响。


Go语言用途

Go 语言被设计成一门应用于搭载 Web 服务器,存储集群或类似用途的巨型中央服务器的系统编程语言。

对于高性能分布式系统领域而言,Go 语言无疑比大多数其它语言有着更高的开发效率。它提供了海量并行的支持,这对于游戏服务端的开发而言是再好不过了。


Go语言环境安装

要搭建Go语言开发环境,我们第一步要下载go的开发工具包,我们可以根据自己的机器操作系统选择相应的开发工具包,比如你的是Windows 64位的,就选择windows-amd64的工具包;是Linux 32位的就选择linux-386的工具包。可以自己查看下自己的操作系统,然后选择,Mac的现在都是64位的,直接选择就可以了。

开发工具包又分为安装版和压缩版。安装版是Mac和Windows特有的,他们的名字类似于:

. go1.9 xxx.pkg

. go19xxx.msi


安装版,顾名思义,双击打开会出现安装向导,让你选择安装的路径,帮你设置好环境比安康等信息,比较省事方便一些。压缩版的就是一个压缩文件,可以解压得到里面的内容,他们的名字类似于:

.go1.9xxx.tar.gz

.go1.9xxx.zip

压缩版我们下载后需要解压,然后自己移动到要存放的路径下,并且配置环境变量等信息,相比安装版来说,比较复杂一些,手动配置的比较多。

Linux下安装

我们以Ubuntu 64位为例进行演示,CentOS等其他Linux发行版大同小异。

下载go1.9.linux-amd64.tar.gz后,进行解压,你可以采用自带的解压软件解压,如果没有可以在终端行使用tar命令行工具解压,我们这里选择的安装目录是/usr/local/go,可以使用如下命令:

tar -C /usr/local -xzf go1.9.linux-amd64.tar.gz

如果提示没有权限,在最前面加上sudo以root用户的身份运行。运行后,在/usr/local/下就可以看到go目录了。如果是自己用软件解压的,可以拷贝到/usr/local/go下,但是要保证你的go文件夹下是bin、src、doc等目录,不要go文件夹下又是一个go文件夹,这样就双重嵌套了。

然后就要配置环境变量了,Linux下又两个文件可以配置,其中/etc/profile是针对所有用户都有效的;$HOME/.profile是针对当前用户有效的,可以根据自己的情况选择。

针对所有用户的需要重启电脑才可以生效;针对当前用户的,在终端里使用source命令加载这个$HOME/.profile即可生效。

source ~/.profile

使用文本编辑器比如VIM编辑他们中的任意一个文件,在文件的末尾添加如下配置保存即可:

export GOROOT=/usr/local/go
export PATH=$PATH:$GOROOT/bin

其中GOROOT环境变量表示我们GO的安装目录,这样其他软件比如我们使用的Go开发IDE就可以自动的找到我们的Go安装目录,达到自动配置Go SDK的目的。

第二句配置是把/usr/local/go/bin这个目录加入到环境变量PATH里,这样我可以在终端里直接输入go等常用命令使用了,而不用再加上/usr/local/go/bin这一串绝对路径,更简洁方便。

以上配置好之后,我们打开终端,属于如下命令,就可以看到go的版本等信息了。

➜ ~ go version
go version go1.9 linux/amd64

这就说明我们已经安装go成功了,如果提示go这个命令找不到,说明我们配置还不对,主要在PATH这个环境变量,仔细检查,直到可以正常输出为止。

Mac下安装

Mac分为压缩版和安装版,他们都是64位的。压缩版和Linux的大同小异,因为Mac和Linux都是基于Unix,终端这一块基本上是相同的。

压缩版解压后,就可以和Linux一样放到一个目录下,这里也以/usr/local/go/为例。在配置环境变量的时候,针对所有用户和Linux是一样的,都是/etc/profile这个文件;针对当前用户,Mac下是$HOME/.bash_profile,其他配置都一样,包括编辑sudo权限和生效方式,最后在终端里测试

Mac安装版下载后双击可以看到安装界面,按照提示一步步选择操作即可。安装版默认安装目录是/usr/local/go,并且也会自动的把/usr/local/go/bin目录加入到PATH环境变量中,重新打开一个终端,就可以使用go version进行测试了,更快捷方便一些。

Windows下安装

Windows也有压缩版和安装版,又分为32和64位以供选择,不过目前大家都是64位,选择这个更好一些。

Window的压缩版是一个ZIP压缩包,下载后使用winrar等软件就可以解压,解压后要选择一个存放目录,比如c:Go下,这个c:Go就是Go的安装目录了,他里面有bin、src、doc等目录。

然后就是环境变量的配置,Window也和Linux一样分为针对所有用户的系统变量,和针对当前用户的用户变量设置,可以自行选择,比如系统变量,针对所有用户都有效。

以Window 7为例,右击我的电脑->属性会打开系统控制面板,然后在左侧找到高级系统设置点击打开,会在弹出的界面最下方看到环境变量按钮,点击它,就可以看到环境变量配置界面了。上半部分是用户变量配置,下半部分是系统变量配置。

我们在系统变量里点击新建,变量名输入GOROOT,变量值是我们刚刚安装的go路径c:Go,这样就配置好了GO目录的安装路径了。

然后修改PATH系统变量,在变量值里添加%%GOROOTin路径,和其他PATH变量以;(分号,Linux下是冒号)分割即可。这样我们就可以在CMD里直接输入go命令使用了。

打开我们的终端,输入go version测试下,好了的话就可以看到输出的信息了。

Window的安装版相比来说就比较简单一些,双击就可以按照提示一步步安装,默认安装路径是c:Go,并且会配置好PATH环境变量,可以直接打开CMD终端使用。


设置工作目录

工作目录就是我们用来存放开发的源代码的地方,对应的也是Go里的GOPATH这个环境变量。这个环境变量指定之后,我们编译源代码等生成的文件都会放到这个目录下,GOPATH环境变量的配置参考上面的安装Go,配置到/etc/profile或者Windows下的系统变量里。

这个工作目录我们可以根据自己的设置指定,比如我的Mac在$HOME/code/go下,Window的可以放到d:codego下等。该目录下有3个子目录,他们分别是:

.
├── bin
├── pkg
└── src
  • bin文件夹存放go install命名生成的可执行文件,可以把GOPATH/bin路径加入到PATH环境变量里,就和我们上面配置的GOPATH/bin路径加入到PATH环境变量里,就和我们上面配置的GOROOT/bin一样,这样就可以直接在终端里使用我们go开发生成的程序了。

  • pkg文件夹是存在go编译生成的文件。

  • src存放的是我们的go源代码,不同工程项目的代码以包名区分。


go项目工程结构

配置好工作目录后,就可以编码开发了,在这之前,我们看下go的通用项目结构,这里的结构主要是源代码相应地资源文件存放目录结构。

我们知道源代码都是存放在GOPATH的src目录下,那么多个多个项目的时候,怎么区分呢?答案是通过包,使用包来组织我们的项目目录结构。有过java开发的都知道,使用包进行组织代码,包以网站域名开头就不会有重复,比如我的个人网站是flysnow.org,我就可以以·flysnow.org·的名字创建一个文件夹,我自己的go项目都放在这个文件夹里,这样就不会和其他人的项目冲突,包名也是唯一的。

如果没有个人域名,现在流行的做法是使用你个人的github.com,因为每个人的是唯一的,所以也不会有重复。

src
├── flysnow.org
├── github.com
├── golang.org
├── gopkg.in
├── qiniupkg.com
└── sourcegraph.com

如上,src目录下跟着一个个域名命名的文件夹。再以github.com文件夹为例,它里面又是以github用户名命名的文件夹,用于存储属于这个github用户编写的go源代码。

src/github.com/spf13
├── afero
├── cast
├── cobra
├── fsync
├── hugo
├── jwalterweatherman
├── nitro
├── pflag
└── viper

那么我们如何引用一个包呢,也就是go里面的import。其实非常简单,通过包路径,包路径就是从src目录开始,逐级文件夹的名字用/连起来就是我们需要的包名,比如:

import (
"github.com/spf13/hugo/commands"
)


第一个Hello World的例子

都准备好了,让我们创建一个hello项目,测试一下。我的项目的路径为src/flysnow.org/hello/

packagemain

import"fmt"

funcmain() {
fmt.Println("Hello, World!")
}

Go版Hello World非常简单。在src/flysnow.org/hello/目录下运行go run main.go命令就可以看到打印的输出Hello World,下面解释下这段代码。

1.package 是一个关键字,定义一个包,和Java里的package一样,也是模块化的关键。 2. main包是一个特殊的包名,它表示当前是一个可执行程序,而不是一个库。 3. import 也是一个关键字,表示要引入的包,和Java的import关键字一样,引入后才可以使用它。 4. fmt是一个包名,这里表示要引入fmt这个包,这样我们就可以使用它的函数了。 5. main函数是主函数,表示程序执行的入口,Java也有同名函数,但是多了一个String[]类型的参数。 6. Println是fmt包里的函数,和Java里的system.out.println作用类似,这里输出一段文字。

整段代码非常简洁,关键字、函数、包等和Java非常相似,不过注意,go是不需要以;(分号)结尾的。

运行程序

运行程序很简单,只需要在相应的目录中,执行 如下语句即可:

go run Hello.go


安装程序

安装的意思,就是生成可执行的程序,以供我们使用,为此go为我们提供了很方便的install命令,可以快速的把我们的程序安装到$GOAPTH/bin目录下。

go install flysnow.org/hello

打开终端,运行上面的命令即可,install后跟全路径的包名。 然后我们在终端里运行hello就看到打印的Hello World了。

➜ ~ hello
Hell World




                                                         


以上是关于Go语言专题:为什么要学习Go的主要内容,如果未能解决你的问题,请参考以下文章

为什么一定要学Go语言

链论坛 怎么学习Go语言?

Go语言专题:go语言切片

怎么学习golang

Go语言能做啥?

go语言学习方法