【阅读】为什么学习go

2020/01/12 ARTS go

原文

Why should you learn Go?

## 概述

  1. 过去几年,一颗新星正冉冉升起,他就是go语言。没有比一门新语言更令开发者高潮的吧?(不接受反驳)所以呢,作者就学了4到5个月就开始要吹go了,且看他如何吹(我也是边看边敲的)。
  2. 本文主旨是解释当前的计算机软硬件处于哪个发展阶段,以及为啥我们需要一门向go这般的新语言。如果没有问题,也就不存在什么解决办法是不是。注意,这里不是教hello, world!的。

硬件限制

  1. 摩尔定律在凋零。2004年,Intel 推出奔腾4处理器,3.0GHz的时钟频率。现在,俺的MBP2016的时钟频率是2.9GHz。所以呢,一个十年过去(这篇文章是2017年写的),处理性能几乎没啥变化(四舍五入,忽略不计)。

    img

    1. 看看上面这张图,单线程性能,时钟频率,在过去十年几乎是稳定的。如果你想多塞点晶体管进去看能不能提高性能,那你就错了。你要问我为什么,我也说不清,无非是在那个量级上,量子相关属性开始有影响(量子隧道?),再多塞点晶体管已经越来越不容易了,代价越来越大,性价比不高了。
    2. 当前的解决方案是:厂商给处理器多加核心,四核八核都已经很常见了;引入超线程;引入跟多的缓存增加性能。
    3. 每个解决方案也有自己的局限性。缓存也有它的物理限制—-越大的缓存,获取数据也越慢。多核也有代价,而且也不能无限增加啊。多核处理器可以同时跑多线程,这就带来了并发的问题了。后面再说。
    4. 既然不能依赖硬件的改进,剩下唯一的办法就是软件更高效。可惜,当代编程语言并不是那么有效率。

    Go有goroutines!!

    1. 多核在不远将来的趋势是核心数的进一步增加;当今的应用也使用了很多微服务来维护数据库连接,消息队列以及缓存等。所以软件还有编程语言应该更容易支持并发,并且随着核心数的增加可扩展。
    2. 现在很多语言(如Java,Python等)都是从上世纪90年代单线程环境发展起来的。虽然很多支持多线程,但是真正的问题其实是并发执行,线程锁,竞争条件,死锁等。这么些个令人头疼的问题,让创建多线程的应用很麻烦,尤其在这些语言上。
    3. 想想吧,在Java上创建一个线程并不能有效利用内存。每个线程都要在堆上消耗大约1MB,几千个线程跑起来的话,堆的压力那是很大的,很容易内存不足。线程间的通信也挺麻烦的。
    4. 来来来,看看2009年发布的go。这时的多核都很常见了,Go创建时就是时时把并发问题放在心上的。它用goroutines,而不是线程。每个goroutine几乎只消耗2KB,所以百万goroutines都不在话下。
    5. 其他的好处还有:
      1. Goroutines具有可增长性的分段式栈,意味着如果需要,可以使用更多的内存。
      2. Goroutines具有比线程更快的启动时间。
      3. Goroutines具有内建的原语来进行他们之间的通信(即channels)。
      4. 在共享数据结构时,Goroutines可以避免使用互斥锁。
      5. Goroutines与OS线程并不是1:1的映射关系,一个goroutine可以再多个线程上运行。多个goroutines也可以多个OS线程上运行。
    6. 综上,Go既可以提供像Java,C/C++那样强大的并发处理能力,也可以让并发的执行代码像Erlang一样显得直接且漂亮。

    Go直接在硬件上运行

    C/C++相比于其他高级语言像Java/Python,一个显著的优势是性能。C/C++是编译型语言,而不是解释型的。

    处理器只懂二进制。当你用Java或是其他基于JVM的语言时,总是会先把代码编译成JVM或是其他虚拟机可以识别的字节码,这些虚拟机时运行在OS之上的。执行时,VM解释这些字节码,转换为处理器可识别的二进制码。C/C++没有虚拟机的概念,它是直接把代码编译成二进制码,减少了执行周期,提高性能。但是释放和分配内存是个令人头疼的问题。与此同时,很多语言都通过垃圾回收器,或是引用计数算法来处理对象分配和释放的。

    Go集大成。像C/C++一样稍低级的语言一样,Go是编译型语言。因此性能与C/C++相当。而且使用了垃圾回收机制来分配和释放对象。所以说,可以跟malloc()free()语句说拜拜了。你说酷不酷!!

    用Go写的代码容易维护

    Go可没有其他语言那种疯狂的语法,紧凑、干净的语法你值得拥有。

    创建这门语言时,Google的设计师们就已经心中有数了。Google拥有非常庞大的代码库,数以千计的开发者在同一个代码库上工作,因此要求代码必须容易理解,代码的副作用最小。这将使代码容易维护与修改。

    Go有意抛弃了一些现代OOP语言的一些特性:

    1. 没有类。所有代码都只被分成packages。Go只有struct,没有class。
    2. 不支持继承。易于代码修改。像Java/Python这样的语言,如果ABC类继承XYZ类,后者改变某些行为,会导致从XYZ类继承的类产生某些副作用(应该说有些不可预知的效果)。通过移除继承,Go可以使代码更易于理解(当你看代码的时候不用再去找什么基类超类),而且没有构造器,没有注解(应该指Java和Python的@语法),没有范型(这算是缺点吧?),没有异常。

    Go做的这些变化,使之区别于其他语言,有些特点可能不能得到码农的认可。但也不是说丢弃上述特性就写不了代码了。顶多多加几行代码而已。我们可以注意到更积极的一面,代码更干净清晰。

    img

看上图,Go的效率接近与C/C++,语法上如Ruby,Python那样简单。对于码农与处理器来说是个双赢。

不像新晋的其他语言如Swift,Go的语法相当稳定。从2012年发布1.0版本以来都没变化过。后向兼容性尚佳。

Go有Google撑腰

这当然不算技术优势。不过Google有全球最大的云基础架构,较大规模的伸缩性。Go设计出来就是用来解决伸缩性和有效性问题的。这些都是创建自有服务时要面对的情况。

许多大公司也已经使用Go来开发商用应用了。如Adobe,BBC,IBM,Intel还有Medium。

结论

Go与其他OOP语言不同,但是其实大同小异。Go提供了类似于C/C++的高效率,类似于Java的高并发处理能力,类似于Pyhton/Perl的代码简洁性。

无论学不学习Go,硬件限制问题都一直会摆在我们面前,促使软件开发者必须编写更高效的代码。开发者需要熟悉硬件,并做相应的优化。优化的软件可以在更便宜更慢的硬件上(如IOT设备)有效运行,给终端用户带来更好的体验。

后记

这篇相当于提纲挈领,告诉俺们Go为啥时一门建议学习的语言。每一门语言的诞生都是为了解决某个现实的问题。认清这些问题比是否学习某种语言更重要。

Search

    Table of Contents