Google用Go语言解决现代计算难题

计算机一直在演化,但是编程语言并没有以同样的速度演化。现在的手 机,内置的CPU核数可能都多于我们使用的第一台电脑。高性能服务器拥有 64核、128核,甚至更多核。但是我们依旧在使用为单核设计的技术在编程。

编程的技术同样在演化。大部分程序不再由单个开发者来完成,而是由处 于不同时区、不同时间段工作的一组人来完成。大项目被分解为小项目,指派 给不同的程序员,程序员开发完成后,再以可以在各个应用程序中交叉使用的 库或者包的形式,提交给整个团队。

如今的程序员和公司比以往更加信任开源软件的力量。Go是一门开源的编程语言,目的在于降低构建简单、可靠、高效软 件的门槛。尽管这门语言借鉴了很多其他语言的思想,但是凭借自身统一 和自然的表达,Go程序在本质上完全不同于用其他语言编写的程序。Go 平衡了底层系统语言的能力,以及在现代语言中所见到的高级特性。你可 以依靠Go语言来构建一个非常快捷、高性能且有足够控制力的编程环 境。使用Go语言,可以写得更少,做得更多。Go语言是一种让代 码分享更容易的编程语言。Go语言自带一些工具,让使用别人写的包更容易, 并且Go语言也让分享自己写的包更容易。

Go语言开发团队花了很长时间来解决当今软件开发人员面对的问题。开发 人员在为项目选择语言时,不得不在快速开发和性能之间做出选择:C和C+ +这类语言提供了很快的执行速度,而Ruby和Python这类语言则擅长快速开 发。Go语言在这两者间架起了桥梁,不仅提供了高性能的语言,同时也让开发 更快速。

在探索Go语言的过程中,读者会看到精心设计的特性以及简洁的语法。作 为一门语言,Go不仅定义了能做什么,还定义了不能做什么。Go语言的语法 简洁到只有几个关键字,便于记忆。Go语言的编译器速度非常快,有时甚至会 让人感觉不到在编译。所以,Go开发者能显著减少等待项目构建的时间。因为 Go语言内置并发机制,所以不用被迫使用特定的线程库,就能让软件扩展,使用更多的资源。Go语言的类型系统简单且高效,不需要为面向对象开发付出额 外的心智,让开发者能专注于代码复用。Go语言还自带垃圾回收器,不需要用 户自己管理内存。让我们快速浏览一下这些关键特性。

1.开发速度

编译一个大型的C或者C++项目所花费的时间甚至比去喝杯咖啡的时间还 长。GO语言使用了更加智能的编译器,并简化了解决依赖的算法,最终提供了 更快的编译速度。编译Go程序时,编译器只会关注那些直接被引用的库,而不 是像Java、C和C++那样,要遍历依赖链中所有依赖的库。因此,很多Go程 序可以在1秒内编译完。在现代硬件上,编铎整个Go语言的源码树只需要20秒。

因为没有从编译代码到执行代码的中间过程,用动态语言编写应用程序可 以快速看到输出。代价是,动态语言不提供静态语言提供的类型安全特性,不 得不经常用大量的测试套件来避免在运行的时候出现类型错误这类bug。

想象一下,使用类似JavaScript这种动态语言开发一个大型应用程序,有 一个函数期望接收一个叫作ID的字段。这个参数应该是整数,是字符串,还是 一个UUID ?要想知道答案,只能去看源代码。可以尝试使用一个数字或者字符 串来执行这个函数,看看会发生什么。在Go语言里,完全不用为这件事情操 心,因为编译器就能帮用户捕获这种类型错误。

2.并发

作为程序员,要开发出能充分利用硬件资源的应用程序是一件很难的事 情。现代计算机都拥有多个核,但是大部分编程语言都没有有效的工具让程序 可以轻易利用这些资源。这些语言需要写大量的线程同步代码来利用多个核, 很容易导致错误。

Go语言对并发的支持是这门语言最重要的特性之一。gomutine很像线 程,但是它占用的内存远少于线程,使用它需要的代码更少。通道(channel) 是_种内置的数据结构,可以让用户在不同的goroutine之间同步发送具有类 型的消息。这让编程模型更倾向于在gomutine之间发送消息,而不是让多个 goroutine争夺同一个数据的使用权。让我们看看这些特性的细节。

3.goroutine

goroutine是可以与其他goroutine并行执行的函数,同时也会与主程序 (程序的入口)并行执行。在其他编程语言中,你需要用线程来完成同样的事 情,而在Go语言中会使用同一个线程来执行多个goroutine。例如,用户在写 一个Web服务器,希望同时处理不同的Web请求,如果使用C或者Java ,不 得不写大量的额外代码来使用线程。在Go语言中,net/http库直接使用了内置 的goroutine。每个接收到的请求都自动在其自己的goroutine里处理。 goroutine使用的内存比线程更少,Go语言运行时会自动在配置的一组逻辑处 理器上调度执行goroutine。每个逻辑处理器绑定到一个操作系统线程上。这让用户的应用程序执行效率更高,而开发工作量显著减少。如果想在执行一段代码的同时,并行去做另外一些事情,goroutine是很好 的选择。

4.通道

通道是_种数据结构,可以让goroutine之间进行安全的数据通信。通道 可以帮用户避免其他语言里常见的共享内存访问的问题。

并发的最难的部分就是要确保其他并发运行的进程、线程或gomutine不 会意外修改用户的数据。当不同的线程在没有同步保护的情况下修改同一个数 据时,总会发生灾难。在其他语言中,如果使用全局变量或者共享内存,必须 使用复杂的锁规则来防止对同一个变量的不同步修改。

为了解决这个问题,通道提供了一种新模式,从而保证并发修改时的数据 安全。通道这一模式保证同一时刻只会有一个goroutine修改数据。通道用于 在几个运行的goroutine之间发送数据。在图1-3中可以看到数据是如何流动的 示例。想象一个应用程序,有多个进程需要顺序读取或者修改某个数据,使用 goroutine和通道,可以为这个过程建立安全的模型。

5.Go语言的类型系统

Go语言提供了灵活的、无继承的类型系统,无需降低运行性能就能最大程 度上复用代码。这个类型系统依然支持面向对象开发,但避免了传统面向对象 的问题。如果你曾经在复杂的Java和C++程序上花数周时间考虑如何抽象类和 接口,你就能意识到Go语言的类型系统有多么简单。Go开发者使用组合 (composition )设计模式,只需简单地将一个类型嵌入到另一个类型,就能复 用所有的功能。其他语言也能使用组合,但是不得不和继承绑在一起使用,结 果使整个用法非常复杂,很难使用。在Go语言中,一个类型由其他更微小的类 型组合而成,避免了传统的基于继承的模型。

另外,Go语言还具有独特的接口实现机制,允许用户对行为进行建模,而 不是对类型进行建模。在Go语言中,不需要声明某个类型实现了某个接口,编 译器会判断一个类型的实例是否符合正在使用的接口。Go标准库里的很多接口 都非常简单,只开放几个函数。从实践上讲,尤其对那些使用类似Java的面向 对象语言的人来说,需要一些时间才能习惯这个特性。

1)类型简单

Go语言不仅有类似int和string这样的内置类型,还支持用户定义的类 型。在Go语言中,用户定义的类型通常包含一组带类型的字段,用于存储数 据。Go语言的用户定义的类型看起来和C语言的结构很像,用起来也很相似。 不过Go语言的类型可以声明操作该类型数据的方法。传统语言使用继承来扩展 结构—Client继承自User , User继承自Entity , Go语言与此不同,Go开发 者构建更小的类型一一Customer和Admin ,然后把这些小类型组合成更大的类 型。

2)Go接口对一组行为建模

接口用于描述类型的行为。如果一个类型的实例实现了一个接口,意味着 这个实例可以执行一组特定的行为。你甚至不需要去声明这个实例实现某个接 口,只需要实现这组行为就好。其他的语言把这个特性叫作鸭子类型-一如果它 叫起来像鸭子,那它就可能是只鸭子。Go语言的接口也是这么做的。在Go语 言中,如果一个类型实现了一个接口的所有方法,那么这个类型的实例就可以 存储在这个接口类型的实例中,不需要额外声明。

在类似Java这种严格的面向对象语言中,所有的设计都围绕接口展开。在 编码前,用户经常不得不思考一个庞大的继承链。

这和传统的面向对象编程语言的接口系统有本质的区别。Go语言的接口更 小,只倾向于定义一个单一的动作。实际使用中,这更有利于使用组合来复用 代码。用户几乎可以给所有包含数据的类型实现io.Reader接口,然后把这个类 型的实例传给任意一个知道如何读取io.Readei•的Go函数。

Go语言的整个网络库都使用了 io.Reader接口,这样可以将程序的功能和 不同网络的实现分离。这样的接口用起来有趣、优雅且自由。文件、缓冲区、 套接字以及其他的数据源都实现了 io.Readei•接口。使用同一个接口,可以高效 地操作数据,而不用考虑到底数据来自哪里。

6.内存管理

不当的内存管理会导致程序崩溃或者内存泄漏,甚至让整个操作系统崩 溃。Go语言拥有现代化的垃圾回收机制,能帮你解决这个难题。在其他系统语言(如C或者C++ )中,使用内存前要先分配这段内存,而且使用完毕后要将 其释放掉。哪怕只做错了一件事,都可能导致程序崩溃或者内存泄漏。可惜, 追踪内存是否还被使用本身就是十分艰难的事情,而要想支持多线程和高并 发,更是让这件事难上加难。虽然Go语言的垃圾回收会有一些额外的开销,但 是编程时,能显著降低开发难度。Go语言把无趣的内存管理交给专业的编译器 去做,而让程序员专注于更有趣的事情。

我们希望读者能认识到,Go语言附带的工具可以让开发人员的生活变得更简单。最后,读者会意识到为什么那么多开发人员用Go语言来构建自己的新项目。

本文来自企鹅号 - 社会学堂媒体

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏PPV课数据科学社区

关于python的编解码(decode, encode)

总结总结,本文仅适用于python2.x 默认编码与开头声明 首先是开头的地方声明编码 # coding: utf8 这个东西的用处是声明文件编码为utf8(要...

39770
来自专栏机器之心

放弃Python转向Go语言:我们找到了以下9大理由

选自Stream 作者:Thierry Schellenbach 机器之心编译 参与:黄小天、李亚洲 转用一门新语言通常是一项大决策,尤其是当你的团队成员中只有...

742110
来自专栏HappenLee的技术杂谈

C++雾中风景12:聊聊C++中的Mutex,以及拯救生产力的Boost

C++从11开始在标准库之中引入了线程库来进行多线程编程,在之前的版本需要依托操作系统本身提供的线程库来进行多线程的编程。(其实本身就是在标准库之上对底层的操作...

26110
来自专栏程序员互动联盟

【编程基础】聊聊C语言-磨刀不误砍柴工

看到上篇讲的《程序和编程语言》引发了大家的热议,小编很是激动。不过被人评论说是不懂编程,小编还真是郁闷了一下下,在此声明小编可是货真价实的“程序猿”哦。言归正传...

45090
来自专栏Java帮帮-微信公众号-技术文章全总结

Java面试系列15

一、Static Nested Class 和 Inner Class的不同 Nested Class (一般是C++的说法),Inner Class (一般...

35340
来自专栏顶级程序员

关于Java面试,你应该准备这些知识点

来自:简书 占小狼 链接:http://www.jianshu.com/p/1b2f63a45476(点击尾部阅读原文前往) 链接:http://www.ji...

39560
来自专栏工科狗和生物喵

【计算机本科补全计划】C++的从头开始之C++基础

正文之前 我要去计算机念博士了!!!高兴!!激动!!!!我要上天啦!!!所以,计算机的前面三年的内容我肯定都要过一遍的。这就是计算机补全计划的真正含义!! 正文...

37470
来自专栏Hongten

python开发_python概述

Python(KK 英语发音:/ˈpaɪθən/,是一种面向对象、直译式计算机程序设计语言,

15920
来自专栏快乐八哥

JavaScript中this关键字使用

在Web开发中,前端掌握JavaScript,后台掌握PHP成为一个趋势。当然后台掌握C#/Java,当然还有Python,Ruby其中的一种,都是可以的。其实...

25590
来自专栏葡萄城控件技术团队

当心那些有歧义的命名

关键点 “别人还能把这个名字理解成什么意思?”通过不断的问自己这个问题来积极检查每一个命名。 事实上,这种富有创造性的、不断尝试“错误理解”的方法,能够有...

22760

扫码关注云+社区

领取腾讯云代金券