- 博主简介:努力学习的大一在校计算机专业学生,热爱学习和创作。目前在学习和分享:数据结构、Go,Java等相关知识。
- 博主主页: @是瑶瑶子啦
- 所属专栏: Go语言核心编程
- 近期目标:写好专栏的每一篇文章
Go 语言从 2009 年 9 月 21 日开始作为谷歌公司 20% 兼职项目,即相关员工利用 20% 的空余时间来参与 Go 语言的研发工作。
谷歌的“20%时间”工作方式,允许工程师拿出20%的时间来研究自己喜欢的项目。语音服务Google Now、谷歌新闻Google News、谷歌地图Google Map上的交通信息等,全都是20%时间的产物。
该项目的三位领导者均是著名的 IT 工程师:
存在即合理,新事物的产生有它的道理
在了解为什么我们需要Go之前,我们先了解现有语言可以大致分为两大类:
首先,语言根据静态和动态类型分为以下两类分为以下两类:
️️总结:静态类型语言,如C++,执行效率高,但编译、学习、开发效率低
️️总结:学习、开发效率高,执行效率低
补充:之前学习Java的时候,有一个概念是多态,其实本质就是一个变量的不同形态(类型),像静态语言,不能给变量赋予不同类型的值,需要采取:继承、接口等方式实现多态。而动态语言采用dynamic typing,就是说变量在运行期间是可变的,意味着对象的多态性是与生俱来的
根据上面分析,
总之,简单来说,在Go之前,没有语言可以兼顾执行效率、开发效率
当然,这只是Go诞生的其中一点
下面列举Goggle公司创造Go语言的原因:
♀️为了解决以上问题,Goggle公司就自己造了个轮子——GO
Go的主要优点
Go的编译器:
最初设计团队的想法是实现Go语言编译的前端,是基于C的gcc的编译器来编译成机器代码。这个前端编译器是目前Go的编译器之一:gccGo
在Go的1.5中,Go团队使用Go编写了Go的编译器(叫作自举),对比与gccgo:1,提高了编译速度,虽然执行速度略有下降;3,增加可编译平台
️️C++为什么慢?
C++是也可以用gcc编译器编译的,所以从编译器角度来说,应该不是编译器使Go更快。很大程度是是Go语言的设计本身
⚠注意:这里我们比较编译速度都是比较的静态编译速度
Go语言·默认·编译方式是·静态编译·不依赖任何动态链接库,可以避免各种动态链接库依赖的问题;编译好后,只要平台是一致的(linux amd64),就可以任意部署,完全不用考虑链接库依赖问题;
♂️静态编译&动态编译:
静态编译
简介: 编译器在编译可执行文件时,会把该文件中使用到的链接库提取出来,链接打包进可执行文件中。编译之后的结果只生成一个可执行文件。
优点:不需要管理不同版本库的兼容问题
动态编译
将外部代码嵌入到当前生成的可执行文件中的就是静态编译,以跳转的方式引用外部代码的就是动态编译
在说回C++为什么慢?
关于模板编译:首先,C++的模板使用,是为了支持泛型编程(这篇文章说的很清楚,这里就不重复造轮子了)。可以看到。编写不同类型的泛型函数,对于编码者来说,确实很方便,但是从那篇文章中,也有可能给编译器增加不必要的编译负担:1,代码膨胀,导致编译时间变长,2,容易出现模板编译错误,且错误信息不易定位
♂️优化:
基于C/C++慢的第一个引入头文件的问题,后生的语言大部分采用import module
代替include 头文件
的方式——Go采用的也是import module
方式(下面是基于C的几种引入头文件的对比)
#include
: include做的事情其实就是简单的复制粘贴,将目标.h文件中的内容一字不落地拷贝到当前文件中,并替换掉这句include。#import:
实质上做的事情和#include是一样的,只不过OC为了避免重复引用可能带来的编译错误(这种情况在引用关系复杂的时候很可能发生,比如B和C都引用了A,D又同时引用了B和C,这样A中定义的东西就在D中被定义了两次,重复了),而加入了#import,从而保证每个头文件只会被引用一次。PCH(PreCompiled Header):
实质上import也还是拷贝粘贴,这样就带来一个问题:当引用关系很复杂,或者一个头文件被非常多的实现文件引用时,编译时引用所占的代码量就会大幅上升(因为被引用的头文件在各个地方都被copy了一遍)。import Modules:
理论上说,想要提高编译速度,可以把所有头文件引用都放到pch中。但是这样面临的问题是在工程中随处可用本来不应该能访问的东西,而编译器也无法准确给出错误或者警告,无形中增加了出错的可能性。Modules相当于将框架进行了封装,然后加入在实际编译之时加入了一个用来存放已编译添加过的Modules列表。如果在编译的文件中引用到某个Modules的话,将首先在这个列表内查找,找到的话说明已经被加载过则直接使用已有的,如果没有找到,则把引用的头文件编译后加入到这个表中。这样被引用到的Modules只会被编译一次,但是在开发时又不会被意外使用到,从而同时解决了编译时间和引用泛滥两方面的问题。基于第二个问题,Go根本没有将泛型编程纳入设计框架,根本不存在模板编译带来的开销。(不过Go1.18中已经支持泛型了)
Go编译速度快的几个原因
import
引用管理方式Go的执行速度,可以参考一个语言性能测试数据网站 he Computer Language Benchmarks Game。
上面我们提到,硬件技术更新快,机器性能大幅提高(eg:多核CPU)。Go语言设计其实初衷也是为了追平编程语言和硬件之间的差距。Go很多特性都是为了并发而生(一些语言也支持并发,但是是一些后期库支持并发和第三方库支持并发,这和Go天生并发的设计是不同的)
Go的并发量可以比大部分语言里普通的线程实现要
这受益于轻量级的Goroutine,轻量化主要是它所占用的空间要小得多,例如64位环境下的JVM,它会默认固定为每个线程分配1MB的线程栈空间,而Goroutines大概只有4-8KB,之后再按需分配。足够轻量化的线程在相同的内存下也就可以有更高并发量(服务器CPU还没有饱和的情况下),同时也可以减少很多上下文切换的时间开销。但是如果你的每个线程占用空间都非常大时(比如10MB,当然这是非常规需求的情况下),Go的轻量化优势就没有那么明显了。
语言设计上支持了并发
垃圾回收(英语:Garbage Collection,缩写为GC),在计算机科学中是一种自动的存储器管理机制。当一个计算机上的动态存储器不再需要时,就应该予以释放,以让出存储器,这种存储器资源管理,称为垃圾回收。垃圾回收器可以让程序员减轻许多负担,也减少程序员犯错的机会
在使用Go或者其他有垃圾回收机制的语言(如Java),无需像C/C++一样进行手动释放内存空间(free()/delete
)
如果对你有帮助还请:点赞+关注+收藏
如果文中有不足还请多多指出