标签 CSP 下的文章

Go语言很无聊…其实它妙不可言![译]

img{512x368}

无聊是一种很奇妙的状态,它可以稀释掉人类的一切情感。- 《古董局中局》马伯庸

GopherCon 2020技术大会上(线上虚拟大会),Jon Bodner为全球gopher们做了主题为“Go Is Boring”的精彩演讲(关注公众号iamtonybai,发送gophercon2020即可得到GopherCon 2020技术大会幻灯片资料)。

img{512x368}

其实早在2020年6月,Jon Bodner就发表过类似主题的文章《Go is Boring…And That’s Fantastic!》。其副标题为:深入探究世界为何依赖简单,可靠且易于理解的技术。本文将在这篇文章的基础上,结合演讲内容做综合翻译与整理,为大家呈现Jon Bodner这个资深程序员对Go语言哲学的理解。

1. 大多编程语言都在堆砌新功能特性

我从事专业软件工程师已有将近23年的时间,而我编写程序的时间也已有38年了。在这个过程中,我使用过很多编程语言。我喜欢编程语言,并且了解它们的新功能特性以及与之前的语言相比所进行的改动。

img{512x368}

如果看一下过去十年的编程语言,您会发现很多变化。C++,Java,Python和JavaScript增加了许多新功能,而一些新编程语言,诸如Rust和Swift等自诞生以来也发生了显著的变化。这一切都非常令人兴奋,但同时也会让你产生一种感觉:有时候,您永远无法跟上这些语言的所有想法。

img{512x368}

图:C到C++,再到更复杂的C++

img{512x368}

图:Java到Java2,再到更复杂的Java3?

JavaScript、Python、Rust、Swift、… …

2. Go没有这么多功能特性

接下来轮到Go了!考量Go的最好方法是思考它没有的功能特性:

img{512x368}

  • Go没有虚拟机或基于LLVM的编译器;
  • Go没有异常(exception);
  • Go没有用户定义的实现继承;
  • Go不支持重载函数、方法或运算符;
  • Go没有不变量;
  • Go没有枚举;
  • Go没有泛型
  • 自2012年Go 1.0发布以来,Go并未添加任何主要功能特性。

Go令人兴奋的一件事是通过goroutine,channel和select原生支持并发。但是,它基于CSP的思想,即Communicating Sequential Processes, 要知道,这可是一个早在1978年就被提出的思想。

这听起来不像是21世纪的编程语言,对吗?

然而,根据Stack Overflow的说法,Go是第三名程序员最想要学习的语言,而且(也许并非巧合)也是第三名最高薪的语言。硅谷的每个创业公司都在使用Go来构建其基础架构。Go语言编写了Docker,Kubernetes,etcd,Terraform,Vault,Consul,Traefik和许多其他前沿项目。那么问题来了?为什么每个人都对这种无聊的语言感兴趣呢?

3. 为什么每个人都对这种无聊的语言感兴趣呢?

在回答这个问题之前,让我们先退一步。

img{512x368}

这是希腊Argolis的Arkadiko桥,它是世界上最古老的桥梁,至今已有3000多年的历史。令人惊讶的是,它仍在使用中。

现在,我们为什么要关心一座古老的桥呢?这是因为软件开发有一个普遍的、但软件工程师们却不喜欢过多谈论的真理:

我们真的不擅长编写软件

我指的不仅仅是办公室里的那个人,你的经理在紧要关头派他去减少bug的数量。我指的是每个人–我,你,还有你能想到的所有著名的开发者。

但那些设计和建造桥梁的人,他们很擅长建桥。桥梁能按时、按预算建成,并能持续服务几十、几百、甚至几千年。造桥,如果你仔细想想,还真有点厉害。而桥梁是这样一种常见的现象,它们也是非常无聊的。当一座桥正常工作的时候,没有人惊奇,而当软件正常工作的时候,大家都有点惊奇。

不幸的是,这个世界非常依赖软件。它对软件的依赖甚至可能比对桥梁的依赖更甚。所以,我们必须以比造桥更快的速度更好地编写软件。

4. 这些年我们对编写软件的了解

在过去的60年中,我们在编写程序方面已经学到了一些东西,其中有很多普遍的共识:

img{512x368}

  • 早发现问题比晚发现问题要好。
  • 人们在管理程序的内存方面很糟糕。
  • 代码评审有助于发现bug。
  • 在任何一个超过一个人的项目中,沟通成本占主导地位。

5. 硬件也不能拯救我们

我们可以把这几件我们知道的事情和另一个已经确定下来的事实结合起来:电脑的速度不再快了。至少不像以前那样了。在20世纪80年代和90年代,CPU每1-2年就会快一倍。但现在情况变了。

img{512x368}

当你看单核性能时,2019年最快的酷睿i9的速度不到2011年最快的酷睿i7的两倍。我们没有变得更快,而是给CPU增加了更多的核心。当你看多核性能时,它更好一些,略微快了2倍多。

限制我们的不仅仅是CPU性能。Forrest Smith写了一篇关于RAM和RAM访问模式对性能影响的精彩博文。其要点如下:

  • RAM比CPU要慢得多,而且差距并没有得到改善,尽管CPU的速度并没有变快多少。

img{512x368}

  • RAM可能是随机访问,但如果你真的这样使用,它的速度很慢。在现代英特尔CPU上,如果数据是顺序的,你可以每秒从RAM中读取40千兆字节左右。如果你进行随机读取,每秒不到半GB。

img{512x368}

  • 有很多指针的代码特别慢。引用Forrest的话。“按顺序将指针后面的值相加的速度低于1GB/秒。随机访问,两次错过缓存,运行速度只有0.1 GB/s。指针追逐的速度要慢10到20倍”。

img{512x368}

6. 无聊带来新的惊喜,我们再来看看Go

鉴于我们知道的这些关于如何构建软件的几个宝贵的东西和我们现有的硬件状况,我们再来重新审视一下Go语言。

1) Go和软件

  • 尽早发现问题

Go语言可能缺乏功能特性,但它却有一套很棒的工具。Go的编译器速度很快,这种快速的编译速度被Go团队认为是一个特点。它可以让你快速查看你的代码是否能编译,如果不能,它可以让你看到问题所在。测试被内置在标准库中,以鼓励开发者测试他们的代码并发现问题。基准测试(benchmark)剖析(profiling)和竞态检查(-race)也是开箱即用的。很少有语言能提供这些工具,它们能让你更容易快速地发现问题。

  • 内存管理

众所周知,Go有一个垃圾收集器。你不用担心跟踪内存,这是一件很奇妙的事情。在编译语言中,垃圾回收是很罕见的。Rust的borrow checker是获得高性能和内存管理的一个迷人的方法,但它实际上把开发者变成了垃圾收集器,这可能很难正确使用;如果你犯了错误,忘记将一些引用声明为弱引用,Swift的ARC仍然会泄漏内存。现在,Go的GC的性能不如这些半自动系统,有些情况下,你需要额外的速度,但在大多数情况下,它肯定是足够的。

  • 代码评审

如果代码评审做得好,代码评审就很重要。为了进行有效的代码评审,你需要确保评审人员专注于正确的事情。低质量的代码评审会把时间花在格式化等事情上。Go在这里提供了很大帮助,因为在评审Go代码时没有有关代码格式的争论,因为所有的Go代码都是按照go fmt的标准代码格式进行格式化。

而代码评审是一个双向的过程。如果你想评审的效果好,你需要确保其他人能够理解你的代码。Go程序应该是简单的,使用一些很好理解的结构,这些结构自语言发布以来就没有改变过。因为没有异常(exception),没有面向方面的编程(AOP),没有继承和方法重写(override),也没有重载(overloading),所以很清楚什么代码在调用什么,在哪里返回值。如果你在Go中减少包级变量的使用,那就很容易看到数据到底是如何被修改的。由于Go的变化很小,你可以避免熔岩流反模式,你可以根据代码中使用的语法特性被引入到Go中的时间点来判断它到底有多老。

  • 沟通成本

Go是如何帮助解决这个问题的呢?我们已经讨论过Go的简单性、稳定性和标准格式化如何让你更容易地传达你的代码正在做什么。虽然这只是其中的一部分,但还有其他的东西。Go的隐式接口帮助团队编写解耦的代码。它们由调用代码定义,以准确描述需要什么功能,这就明确了你的代码在做什么。

2) Go和硬件

让Go成为编译语言的决定得到了回报。当CPU每天都在变快时,在虚拟机(译注:这里所谓的虚拟机是指动态语言的解释器或像jvm之类的字节码运行程序)中运行的解释语言似乎是个好主意。如果你的程序不够快,只要再等一年就可以了。但现在这已经行不通了。编译成原生代码比最新的虚拟机技巧少了很多乐趣,但它能带来很大的性能优势。

让我们用The Benchmark Game的微基准来比较Go与一些在虚拟机中运行的语言的性能。首先我们来看看Python和Ruby与Go的比较。任何小于100%的百分比都意味着比Go快,大于100%意味着慢:

img{512x368}

这里有很多红色(意味着比Go慢的测试)。有一个基准测试是Python更快 (奇怪的是,它不仅是Go的两倍,而且在这个测试中比其他所有语言都快),而Ruby则没有一个测试比Go快。除了那一个情况,这两种语言产生的代码都比Go慢了17%到60多倍。

现在让我们再看看Java和JavaScript与Go的比较:

img{512x368}

这两门语言与Go的性能更为接近。JavaScript在一个基准上比Go快,在其他基准上比Go慢,但JavaScript最坏的情况是比Go慢了三倍左右。

Java和Go的性能相当接近。Java在四种情况下比Go快,在两种情况下差不多,在四种情况下比Go慢。Go做的最差的情况是比Java慢三倍左右,Go做的最好的情况是比Java快50%左右。

我们看到的是,唯一能跟上Go的虚拟机是Java的。Hotspot是令人惊异的技术,但你需要一个世界上最好的工程软件,才能与一个优先考虑编译速度而非优化的编译器达到平衡,这说明了一些问题。而且你要为这种惊人的技术付出代价。Java应用程序的内存使用量要比Go应用程序大出很多很多倍。

还有第二个优势。垃圾收集器管理的垃圾都是不使用的指针。与隐藏指针的语言不同,Go给了你控制权。它让你避开指针,并以一种允许快速访问RAM的方式布局你的数据结构。这也让Go可以使用更简单的垃圾收集器,因为Go程序只是简单地制造更少的垃圾。枯燥无味的工作就是少了。

而我们都知道,CPU正在用更多的内核来弥补速度提升的不足。所以,使用一种能够利用这一点的语言是很好的。这就是Go内置并发支持的目的。有了对并发的语言级支持和一个在多个线程中调度goroutine的运行时库,意味着当你有多个CPU核时,这些线程可以被自然地映射到这些核上。

7. 我不想要我没有得到的那些功能特性

我们已经看到,Go专注于我们所知道的使创建软件更容易、更适合现代计算机的内存和CPU架构的功能和工具。但是其他语言有而Go没有的功能特性呢?也许Go的开发者错过了,那些Go没有的特性能帮助开发者写出了更少错误、更容易维护的代码?好吧,研究人员的研究结果告诉我们,事实并非如此。

2017年一篇名为《Github中编程语言与代码质量的大规模研究》的论文,该论文研究了17种语言的729个项目、8000万行代码、2.9万名作者、150万次提交,并试图回答这个问题:编程语言对软件质量的影响是什么?他们的答案是,差别不大。

“值得注意的是,这些因语言设计而产生的微弱影响,绝大多数是由项目规模、团队规模和提交规模等过程因素主导的。”

另一组研究人员对这些数据进行了第二次研究,并在2019年做了一项名为“关于编程语言对代码质量的影响”的论文。他们的发现更令人惊讶:

“根据手头的数据,不仅无法建立编程语言和代码质量之间的因果关系,甚至它们之间的相关性也被证明是值得怀疑的。”

如果编程语言的选择并不重要,那为什么要选择Go?这些研究表明的是,流程很重要。工具、测试、性能和长期维护的便利性比时髦的功能特性更重要。如果使用得当,Go内置的工具支持更好的流程,同时提供久经考验的功能特性。

这并不是说新功能不好。在过去的几个世纪和几千年里,桥梁建设技术当然在不断进步。但是,你想成为第一个走过一座用全新的理念和未经测试的技术建造的桥梁吗?你会想等一下,让人们测试一下再采用。

软件也是如此。如果我们要建立像桥梁一样可靠的软件基础架构,我们就需要使用像物理基础架构一样经过充分测试和理解的软件技术。这就是为什么Go主要使用20世纪70年代设计的功能特性,我们知道它们是有效的。

Go很无聊….其实它妙不可言。让我们都来用它来构建明天的精彩应用吧。

img{512x368}


“Gopher部落”知识星球开球了!高品质首发Go技术文章,“三天”首发阅读权,每年两期Go语言发展现状分析,每天提前1小时阅读到新鲜的Gopher日报,网课、技术专栏、图书内容前瞻,六小时内必答保证等满足你关于Go语言生态的所有需求!星球首开,福利自然是少不了的!2020年年底之前,8.8折(很吉利吧^_^)加入星球,下方图片扫起来吧!

Go技术专栏“改善Go语⾔编程质量的50个有效实践”正在慕课网火热热销中!本专栏主要满足广大gopher关于Go语言进阶的需求,围绕如何写出地道且高质量Go代码给出50条有效实践建议,上线后收到一致好评!欢迎大家订阅!

我的网课“Kubernetes实战:高可用集群搭建、配置、运维与应用”在慕课网热卖中,欢迎小伙伴们订阅学习!

img{512x368}

我爱发短信:企业级短信平台定制开发专家 https://tonybai.com/。smspush : 可部署在企业内部的定制化短信平台,三网覆盖,不惧大并发接入,可定制扩展; 短信内容你来定,不再受约束, 接口丰富,支持长短信,签名可选。2020年4月8日,中国三大电信运营商联合发布《5G消息白皮书》,51短信平台也会全新升级到“51商用消息平台”,全面支持5G RCS消息。

著名云主机服务厂商DigitalOcean发布最新的主机计划,入门级Droplet配置升级为:1 core CPU、1G内存、25G高速SSD,价格5$/月。有使用DigitalOcean需求的朋友,可以打开这个链接地址:https://m.do.co/c/bff6eed92687 开启你的DO主机之路。

Gopher Daily(Gopher每日新闻)归档仓库 – https://github.com/bigwhite/gopherdaily

我的联系方式:

  • 微博:https://weibo.com/bigwhite20xx
  • 微信公众号:iamtonybai
  • 博客:tonybai.com
  • github: https://github.com/bigwhite
  • “Gopher部落”知识星球:https://public.zsxq.com/groups/51284458844544

微信赞赏:
img{512x368}

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。

Go语言的遗产

本文是gohugo作者Steve Francia在意大利佛罗伦萨举办的GoLab上分享的闭幕演讲讲稿的文字版,该演讲的主题为”Go的遗产”。该演讲讨论了Go语言继承的遗产,以及它是如何尊重这些遗产的,并在最后总结了Go希望留给后来者的遗产。

img{512x368}

演讲胶片

我们有责任保留好留给我们的遗产,并留下值得我们子孙后代继承的遗产 – 克里斯汀·格雷格(Christine Gregoire)

1. Go语言之前

img{512x368}

1950年

在1950年代后期,人们对每台新计算机如何产生自己独特的语言而感到不安。当时,编程语言是由硬件制造商提供的,并且因型号而异。跨计算机且保持一致的第一门编程语言是Fortran,但这仍然仅适用于其制造商IBM(生产的计算机)。而后,人们成立了一个委员会,该委员会的使命就是设计第一种真正通用的、独立于机器的编程语言。

img{512x368}
图:编程语言历史Babel塔,CACM封面,1961年1月

1960年

1960年1月,有13位计算机科学家在巴黎举行了一次空前的会议,旨在(设计)开发出这样一种语言。美国派出了6位代表,欧洲派出了7位代表。

会议上无休止、令人振奋的讨论也让科学家们筋疲力尽。当一个人的好主意与他人的坏主意一起被抛弃时,一个人就会变得更加恼火。然而,在整个会议期间内,大家都没有懈怠,持续地努力投入着。

最终这13名科学家的思想碰撞产生了良好的化学反应 – Alan Perlis

Algol

img{512x368}

这是一种远远超越其时代的语言,它不仅是对其前辈的一种改进,而且对其所有后继者也产生了重大影响。- Tony Hoare关于编程语言设计的提示– 1973年

img{512x368}

之后,原本一脉相承的语言出现了分裂:

  • Pascal这一分支在欧洲蓬勃发展,有许多继任者,包括ModulaOberon

img{512x368}

  • C语言在美国激增,激发和促进了C++、C#、Java以及JavaScript、Python、Perl、PHP和许多其他语言的诞生和发展。

img{512x368}

  • 到2007年,存在的数十种编程语言都可以追溯到其共同祖先:Algol。

img{512x368}

1964年

我们的并发故事始于Doug McIlroy,他在1964年提出了一些新的想法,这些想法最终演化为Unix Pipes。

当有必要以另一种方式处理数据时,我们应该有一些耦合程序的方法,例如像将花园软管拧入另一部分那样。这也是IO的方式。- Doug McIlroy

背后故事

在1970年至1972年的一段时间内,我不时说:“如何做这样的事情?”,然后我提出了另一个建议,另一个建议,另一个建议。有一天,我想出了一种shell语法用于支持管道使用,Ken说:“我要去实现它!”他厌倦了听到所有这些内容……[并且]他说,“要去实现它”。他没有完全按照我为管道系统调用所建议的去做。他发明了一种更好一点的东西,终于又改变了今天的样子。他在一夜之间将管道符放入了Unix(并且他做到了)……。

麦克罗伊(McIlroy)引述:布赖恩(Brian)的墙上还挂着一张纸,在那张纸上我谈到了像花园软管那样将流(stream)拧在一起。所以这个想法在我脑海中徘徊了很长时间。

同时,在Thompson和Ritchie在黑板上,草拟了一个文件系统,我正在草拟如何在黑板上进行数据处理,方法是将一系列过程串联在一起,并寻找一种将过程连接在一起的前缀表示法语言。之所以失败,是因为很容易说出“cat into grep into……”或“who into cat into grep”等等。这么说很容易,而且从一开始就很清楚,这就是您想说的。但是这些命令具有所有这些附带的参数。它们不仅具有输入和输出参数,还具有选项,并且在语法上还不清楚如何将这些选项插入以前缀表示法编写的链中,比如:cat(grep(who …))。在句法上很多人不知道如何做。所以我把这些非常漂亮的程序写在黑板上,用的语言不够强大,无法应付现实。因此,我们实际上并未这样做。

1978年

到1978年,在对多处理器进行编程的背景下,有许多提议的方法被用于通信和同步。共享内存是最常见的通信机制。

托尼·霍尔(Tony Hoare)发表了一篇论文,该论文改变了一切。它比时代提前了几十年。他称他的论文为:”通讯顺序进程,communicating sequential processes”,就是大家熟知的CSP。

img{512x368}

  • 进程(Processes):执行单元
  • 顺序(Sequential):每个进程都作为一个普通的单线程程序运行
  • 通讯(Communicating):进程如何协调
  • 没有内存共享
  • 没有线程,没有互斥体

Hoare的论文提出了一种语言,每个进程(或者作为一个普通的单线程程序)按顺序执行,通过无缓冲通道(unbuffered channel)相互通信。Hoare的通信进程比典型的Unix Shell管道更通用,因为它们可以以任意模式连接。

img{512x368}

三个语言分支因Hoare的CSP论文而诞生:ErlangOccamNewsqueak

  • 1983年诞生的Occam最接近CSP论文(由Hoare推荐)
  • Erlang在80年代后期专注于CSP的功能方面,并使用mailbox在进程之间进行通信
  • Rob Pike(Newsqueak之父)追逐了并发白鲸(the concurrency white whale)长达20年

img{512x368}

Go是第一种可以同时拥有欧洲和美国语言设计分支传统的语言。实际上,它已经统一了这三个分支

2016年,黑客新闻评论(Hacker News)上的一则帖子称Go语言时停留在70年代的一种语言,这引起了一些对Go的批评……

2. 对过去伟大思想的复兴

img{512x368}

编程语言发展的四波浪潮

img{512x368}

  • 第一波浪潮:语言扩张 – 巴别塔

特征:多样化。很久以前,语言是多种多样的,并在在思想、方法和意见等方面体现出多样性。

  • 第二波浪潮:语言的标准化

特征:快速、复杂且对开发不友好。语言的标准化发生了数十年。到2000年代,事情开始停滞。他们融合为两个阵营:Java/JVM和C/CLR。C++、Java、C#都非常相似。

  • 第三波浪潮:脚本语言

特征:慢、不安全但对开发友好。脚本语言作为对上述语言的复杂性和痛苦的回应而应运而生。它们开发快速而松散,对开发人员友好,但缺乏性能和安全性。

  • 第四波浪潮:恢复

特征:快速、安全、对开发人员友好

Go是对这些语言的复杂性和痛苦的一种反应,也是对脚本语言快速开发和松散本质的反应。

Go恢复了早期语言的简单性和灵活性,增加了现代语言的安全性和开发友好性。Go以一种非常真实的方式复兴了许多伟大的想法,这些想法终于准备就绪。

Go给人的感觉就像是来自60年代,70年代,80年代,90年代,00s,10年代的语言……Steve Francia 2019

Go感觉像这样是因为它由过去60年来的许多伟大构想组成。

img{512x368}

现在,我想谈谈Go中的3种特定功能(简单、并发和Go的OO)以及这些思想起源的4种语言(Oberon、Newsqueak、Simula和Smalltalk)。在Go恢复它们之前,许多思想被遗忘了。

1988年

简单易读的结构和语法: Oberon&C

Niklaus Wirth负责Algol-W,Pascal,Modula。现在是1988年,他的最新语言是Oberon

Oberon的程序结构,以“hello, world”例子为例:

MODULE hello;

IMPORT Out;

BEGIN
    Out.String("Hello, World"); Out.Ln
END hello.

Oberon围绕着爱因斯坦(Albert Einstein)的座右铭设计:“使事情尽可能简单,但不要过于简单。”

程序结构非常简单。

下面是Go的”hello world”程序结构:

package main

import "fmt"

func main(){
    fmt.Println"hello world")
}

这个例子看起来应该很熟悉,它直接采用Oberon的结构。

我们再来看看Oberon的声明结构

CONST n = 42;
TYPE mystring = ARRAY 32 OF CHAR;
VAR s: mystring;

PROCEDURE squared(x:INTEGER):INTEGER;
BEGIN
    RETURN x * x
END squared;
VAR b,c: INTEGER = 1,2;

再来看看Go的声明结构:

const n = 42

type mystring string

var s mystring

func squared(x int) int {
    return x*x
}

var b, c int = 1, 2

在Go和Oberon中,声明都是从左到右(名称,类型,可选值),这恰与C相反,在C语言中,类型放在前面。

很多人看到Go后会问为什么我们要翻转C语法,他们错误地认为Go的声明结构来自C语言。它不是,它来自Oberon。

Go使用了Oberon形态,但却用C的token:

  • {}代替BEGIN END
  • ++,– 代替(内置)的INC和DEC
  • != 代替#
  • %代替MOD
  • || 代替OR
  • []代替ARRAY
  • 结构体代替RECORD
  • *代替POINTER TO

虽然结构来自Oberon,但Go使用的token却来自C。

  • 这里没有太多,这就是重点。语法和结构都很简单。
  • 没有继承,没有层次。没有复杂的作用域(scope)系统。
  • 它们尽可能简单,但并不过于简单。

您可以看到Go如何采用Oberon的简单结构,但是删除了笨拙的语法,并采用C语言的更加优雅和熟悉的语法替换了它们。

这样做的结果是一种非常易读的语言诞生了。

1989年

并发与Newsqueak

罗伯·派克(Rob Pike),他于1989年在贝尔实验室工作。他在这里设计了Newsqueak

  • Newsqueak是一门用于研究和探索的编程语言
  • 它致力于在Sequeak基础上添加实用的、切实可行的并发(concurrency)支持
  • Newsqueak语法上类似C
  • 像CSP一样,Newsqueak使用Channel作为Process的集合点

Rob Pike的Newsqueak在语法上看起来像C,但对并发支持的更好。Squeak用于设计菜单和滚动条之类的设备,Newsqueak解决了同样的问题,但涉及范围更广:Newsqueak用于编写整个应用程序,尤其是窗口系统。

Newsqueak-Prime Sieve pt.1

译注:Rob Pike拿手的素数筛例子

counter := prog(end: int, c: chan of int) {
    i: int;
    for(i = 2; i<end; i++) c<-=i;
};

filter := prog(prime: int, listen, send: chan of int) {
    i: int;
    for(;;)
        if((i=<-listen)%prime)
            send<-=i;
};

Newsqueak-Prime Sieve pt.2

sieve := prog(c: chan of int) {
    for(;;) {
        prime := <-c;
        print(prime, “ “);
        newc := mk(chan of int);
        begin filter(prime, c, newc);
        c = newc;
    }
};

count := mk(chan of int);

begin counter(10000, count);
sieve(count);

与CSP和Squeak不同,Newsqueak将channel视为一等公民:channel可以存储在变量中,可以作为参数传递给函数,甚至channel自身也可以通过channel发送。

另外”<-c(receive)”表达式也是第一次在这里介绍。

channel和routine

Go:

c := make(chan int)
c <- 1
x = <-c
go f(x)

vs.

Newsqueak:

c := mk(chan of int);
c <- = 1;
x = <-c;
begin f(x);

我们看到:Go的并发方法几乎与Newsqueak完全相同,channel和 goroutines的使用方式也是相同的。

select

Newsqueak还使用了看起来与Go的select语句非常相似的select。

select {
    case msg1 = <-c1:
        print(“received”, msg1, “\n”);
    case msg2 = <-c2:
        print(“received”, msg2, “\n”);
}

您可以清楚地看到Go并发的基础在25年前是如何在Newqueak中被建立起来的。Go采纳了这些”老想法”,并对其进行了改进,使其可以投入生产。

Ryan Dahl: Node.js的创建者的访谈(2017)

我喜欢Go的编程模型。使用goroutine是如此简单和有趣……如果您要构建服务器,那么我无法想象使用Go以外的任何工具。Goroutine使Go的并发变得简单。

1965年

面向对象基础(Smalltalk)

OO在C++/Java之前就已存在,在C++和Java重新定义面向对象之前。

什么是面向对象?

  • 附加到数据对象的过程(Procedure)
  • Procedure的可重用性

Procedure+数据

img{512x368}

Simula继承了Algol,并在其中添加了对象,类,继承和子类。 Simula被认为是第一种面向对象的编程语言,并且在Smalltalk和所有随后的OO语言的开发中具有重要的影响力。

Simula改变了一直以来的从Procedure的角度来看的思维方式,…他将其翻转为…面向对象的视角,即在每种类型的对象中,您都有处理它的所有方法。- Small Talk的实现者Dan Ingalls

1980

接下来是Smalltalk,其中一切都是对象,并且仅通过发送消息与对象进行通信。

img{512x368}

我确实发明了“面向对象”这个术语,但这是一个错误的选择,因为它没有强调消息发送这个更重要的思想。 – Alan Kay: 从A到Z的编程语言:Smalltalk-80 – 2010

1989年

Procedure重用

我们将讨论两个出版物:

如果系统的任何部分取决于另一部分的内部结构,那么复杂度会随着系统大小的平方而增加 – Dan Ingalls面向对象编程— 1989年

继承。 我们看到了继承带来的这种指数级复杂性

对于使用半新的OO语言进行编程的任何人,这应该看起来都很熟悉。关系线无处不在。 – SPAGHETTI CODE的诞生

论文《强类型面向对象编程的接口》中所提到的系统提供了Ada和Modula-2之类的语言中的模块接口的优点,同时保留了可表达性,使无类型的面向对象的语言(如Smalltalk)具有灵活性。

Go interfaces

type Point interface {
    X() int
    Y() int
    Move(int,int)
    Point Equal(Point) bool
}

Go团队在实现interface时并不知道到该论文的存在。由于这两种方法的明显相似性,后来与他们share了该论文。

Go采取了非常相似的方法,但是对上面论文中想法进行了改进,因为Go接口是隐式的,这使Go应用程序解耦并提供了极大的灵活性。

当您尝试分解一个复杂的问题时,您想要尝试将其分解为尽可能少的部分,并且希望它们尽可能独立。 – Dan Ingalls 面向对象编程— 1989

Go的interface和method采用尽可能独立的方式。只要添加正确的方法,任何类型都可以满足任何接口。可以在满足该接口的类型之前或之后定义一个接口。事实证明,这种方式是有效的,而且效果很好。

Go的OO

  • method提供任何类型的消息发送机制
  • 接口通过动态调度多态性提供可重用性

Go提供了像Smalltalk定义的那种面向对象编程,只是更加贴近实际,即使它不包含类,对象或继承。

  • Smalltalk: OO是关于消息发送
  • Go的interface允许方法像Smalltalk的消息一样自由使用,但是是在一种有类型的语言中使用

3. Go的设计哲学

img{512x368}

2007年

在一次耗时45分钟的C++构建过程中……

罗勃·派克:把时钟拨回到2007年9月,当时我正在对一个巨大的谷歌C++程序做一些微小但重要的优化工作,你们都与这个庞大的程序做过交互。我得这个编译过程在我们的巨大的分布式编译集群上跑了约45分钟。我收到一条消息:为C++标准委员会服务的几位Google员工将进行一个演讲,他们将告诉我们C++ 11的新功能。

在一个小时的演讲中,我们听到了有关计划中的35个新功能的消息。……这时我问自己一个问题:”C++委员会真的相信C++的不足之处在于它没有足够的功能吗?” 当然……,简化语言而不是为其添加更多功能将是一个更大的成就。Rob Pike和他的办公室同事(Robert Griesemer、Ken Thompson)回到了办公桌前。这真的让他们开始思考…

现代实用的编程语言应该是什么样?到45分钟构建完成时,他们已经有了一个充满想法的白板。

语言设计的进化过程

我们从头开始构建,仅从C中借鉴了一些小东西,例如运算符和大括号,以及一些通用关键字。当然,我们还借鉴了我们所知道的其他语言的想法。- 罗伯·派克(Rob Pike)

少即是(指数级的)多 – 2012年,在谈到Go的灵感时 Rob Pike

Go的众多祖先和对Go有影响的语言:

img{512x368}

我要说的是,没有哪位语言设计师比这三位语言设计师(Rob Pike, Robert Griesemer, Ken Thompson) 具有更广泛或更深的语言设计专业知识。他们对以前发生的事情有很丰富的了解,他们知道该采摘什么。他们还具有事后观察的优势(后发优势)。这是修复他们认为可以做得更好的事情的机会。

进化不是革命

  • 原则1:大多数思想都来自先前的思想

大多数思想根本不是新事物

进化不是革命:新语言应该巩固而不是发明新特性

等待良好的设计

  • 原则2:No是暂时的,Yes是永远的。

在Go的整个历史中,有很多这样的实例。通常的想法是,在设计语言时,不会出现“撤消(undo)”的情况。如果您今天说“No”,那么您明天总是可以说“Yes”,但是如果今天您说“Yes”,那么您将在很长一段时间或永远被它“困”住…。

如有疑问,请将其排除在外。- Joshua Bloch:关于设计的对话– 2002

共识驱动的设计

  • 原则3: 应该使一切都尽可能简单,但不要过于简单。-爱因斯坦

当我们三个人开始时,这纯粹是研究。…我们从一个想法开始,即我们三个人都必须针对该语言的每个特性进行讨论,因此,无论出于何种原因,都不会在该语言中放入多余的垃圾。 – 肯·汤普森(Ken Thompson)访谈– 2011年,肯从Bell Labs学习了这种做法

有两种构建软件设计的方法。一种方法是使其变得如此简单,以至于显然没有缺陷。另一种方法是使其变得如此复杂,以至于没有明显的缺陷。 – 托尼·霍尔(Tony Hoare)皇帝的旧衣服-1981年,Go采取了第一种方法,而大多数其他语言都采用第二种方法。

快速迭代期待并实现大规模改变

  • 最后一个原则是快速迭代的原则。

当您处于语言的设计阶段时,您将需要进行频繁且有时是巨大的更改。朝着这个期望前进,并围绕它建立您的流程。

4. 今天的Go

img{512x368}

我们来看Go如今是如何演变的。

2019年

Go今天是如何继续进行演化的。

上面的4条原则在该语言的初期,在发行稳定版之前和被采用之前都非常有效。

但我们现在的处境非常不同。我们不再能够将所有贡献者都放在白板上,甚至不能放在如此大的房间中(译注:Go目前的contributor数量庞大)。

现在,我想与大家分享Go项目今天如何进行更改的。

我们的原则是“等待良好的设计”,这似乎意味着这是一种消极的活动,但这与事实相去甚远。真正的意思是,除非我们非常有信心采用正确的方法,否则我们不会接受更改。

这意味着所有问题的默认答案是“否”。“是”的成本非常高,因此需要一个压倒性的理由。

对一件事说“Yes”意味着对其他一切都说“No”。

软件复杂性的主要原因是供应商不加批判地采用了用户想要的几乎所有功能。人们似乎将复杂误解为先进。

不可理解的应该引起怀疑而不是钦佩。- Niklaus Wirth, 1995年

我们对Go进行了长期展望。为下一个十年或两个或更多个而设计。大多数项目的运行时间要短得多,因此通常会接受第一个可通过的解决方案。

随着时间的流逝,经过长时间这种训练的人们已经意识到:如果一个好主意会被接受,或者反之,不好的主意会被拒绝。

由于我们的长期观点,在为Go项目做出贡献时人们挣扎并不罕见。当他们的想法不能被接受时,许多人感到被亲自拒绝。

或更糟糕的是,人们会感到自己不合格或不称职。我记得有这种感觉。

几年前,我创建了一个网站引擎Hugo,随着时间的推移,它成为Go模板的第一用户,并在此过程中发现了几个问题。尽管如此,我感到非常没有资格报告这些问题,因为我认为创建这些库的“专家”显然比我了解更多,并且我无能为力。在第一次或第二次Gophercon上,我碰巧在午餐台上站在Russ Cox旁边,我们开始交谈。他强烈鼓励我报告这些问题,并让我知道他们多么地需要反馈。

几年后,我加入了Go团队,并从这个经验中学到了很多。我观察到的一件事是,Go团队那些加入较久的核心成员有一件事比大多数其他成员都做得更好,这可能不是您的想法。Go团队的老成员已经非常习惯于听到“不”的声音。我们团队成员的提议被拒绝的比率很高,甚至高于Go团队之外的提议。我们已经了解到,每个“No”都与拥有正确的“Yes”仅一步之遥。

因为我们经常听到“No”的声音,所以我们同情别人被拒绝的感觉。

今天我要传达给您的信息是您受到重视和需要。请继续尝试。在接下来的十年或二十年或更长的时间内,您是Go演化的关键部分。

Go开发流程

Go开发流程

实验流程简化始于今年早些时候,Russ Cox谈论了我们用来对Go进行更改的流程以及它的演变方式。在演讲中,他讨论了实验的两个步骤,并简化了我们的迭代过程。

我们的过程不是为了速度而建立的,而是为了正确。我们花费大量时间进行实验和简化,然后完善自己的想法,直到它们正确为止。

你们都是Go伟大实验的一部分,并且是继续构建Go的过程的关键部分

我想与大家分享3种方法,每个人都可以为Go做出贡献。

  • 使用Go -> 识别问题 -> 您遇到的事情/体验并写下来。
  • 您有想法-> 编写建议 -> 纳入反馈
  • 您阅读提案 -> 阅读评论 > 添加您的声音

img{512x368}

Go开发过程:实验 -> 简化 -> 最终交付。通过此提炼过程,想法将准备就绪,我们将进行交付。我想对过程的这一部分及其工作原理提供更多见解。

共识驱动的设计

  • 误解:谷歌有一小群“决策者”
  • 真相:评论者之间达成共识

关于提案过程的事实

  • 事实上,大多提案提案都很小
  • 几乎所有提案的讨论最终都在参与者(评论员)之间达成了共识。
  • 提案审核委员会主要进行一些“园艺劳动”(译者:社区行为培养)

您看到这不是一件非常迷人的工作。我们评论的大多数问题都要求您澄清问题或什么也不做,让对话继续进行。我们还会考虑谁在对话中丢失,并邀请他们加入对话。

当讨论似乎已经解决(赞成或反对)时,我们将关闭其中的一小部分。

让我们看一下最近的一个建议。这只是从最近提案池中随机选取的一个。

它具有一些有趣的属性:大量参与,来自9个参与者的25条评论引用用户问题(体验)。早期该issue尚无共识(由点赞决定)。

在对该想法进行讨论和完善之后,很明显已经达成了普遍共识。

它被标记为“可能接受”,并且留下足够的时间窗口允许任何人提供我们不接受的理由。

这是一组最近审核的提案。您会注意到,他们每个人都引用了之前的评论,并根据这些评论提出了建议。

在提案审核委员会中,通常会有一个人留下评论,但代表所有出席者。Russ Cox通常志愿承担了这个角色,这就是为什么所有这些issue上面都加上他的名字的原因。在大多数情况下,此窗口不会附加注释。我们觉得这个窗口虽然很少使用,但对于建立共识的过程至关重要。

变化是缓慢发生的

这是设计使然。这是缓慢的、谨慎和有条不紊的,以确保我们最终达到想要的目标。

过去十年的主要里程碑

尽管Go的变化缓慢,但增长迅速。我想了解一下过去十年中的一些主要里程碑。

img{512x368}

  • 2009年, Go语言开源,Gopher诞生,Go脱离了Google的实验场;
  • 2010年,获得年度TIOBE语言,Bossie奖,引入append和go tour;
  • 2011年,gccgo合并到GCC中,引入gofix,YouTube在生产中采用了Go;
  • 2012年,Go 1.0发布!发布Go1兼容性承诺;在Google内部发布第一项Go生产服务

img{512x368}

  • 2013年,Packer,Docker,Hugo用Go编写;6个月发布周期;第一个Go大会举行(日本东京)
  • 2014年,Kubernetes使用Go开发;代码仓库由Mercurial→Git;第一次美国和欧洲会议;Go项目贡献者达到500名;
  • 2015年,Go编译器使用Go重写,实现自举;GC精化; Women Who Go&GoBridge born; 印度、中国第一次go大会举行;
  • 2016年,支持HTTP/2和Context;第一次拉丁&中东Go大会举行;最受喜欢的5门编程语言;第一次Go用户调查;贡献者达1000名;

img{512x368}

  • 2017年,GC小于ms级的暂停; 引入type alias;开发人员想要使用编程语言第一名第一次); 13次会议; 第一届贡献者峰会
  • 2018年,引入Go模块;来自Go团队之外的贡献者人数首次超过Go团队;19次Go会议;Go新品牌和logo发布;PR数在github排名第四; 开发人员打算学习的语言中排名第一

5. Go的遗产

img{512x368}

没有时间机器可以达到未来。未来的到来缓慢而又出乎意料。我们不知道Go或世界将会发生什么。但是我们确实知道我们想留下什么标记。

  • 我们希望Go能够留下创新的遗产

Go向主流受众带来了创新的想法,例如goroutine,channel,简单的interface。这些想法现在正在其他语言中出现,我们为这一趋势继续感到高兴。

Go fmt于2009年推出时颇有争议。现在,大多数语言都采用了类似的方法。

也许我们最有影响力的遗产将是,我们像Go一样激励人们挑战既定的规范,并在各处寻找灵感。

  • 我们希望Go留下增强信心和能力的遗产

Go使开发人员能够编写生产服务器软件而无需C和C++所需的额外专业知识,而无需现代Java的复杂性,也无需解释语言的性能成本。

Go比其他任何语言都更能使人们把他们的想法变成现实。当我第一次开始撰写Hugo时,我个人感觉到了这一点,这是Go最吸引我的地方。

其他那些也被赋予了类似的能力和信心的人,其中许多人在本次会议上谈到了Go的创造性用途,包括Florin的家庭自动化研讨会,Ron的机器人,Elias的GUI等。

  • Go改变生活。

我有幸环游世界,在任何地方遇到的男人和女人,他们通常没有CS背景或学位,但能够学习Go并用它来创办公司,获得更好的工作并改善他们和他们家人的生活。

遗产不会为人们留下任何东西。它在人们身上留下了一些东西。- 彼得·斯特普尔

我们每个人都受到过往历史的影响。我们是遗产。我们被影响,我们影响别人。


我的网课“Kubernetes实战:高可用集群搭建、配置、运维与应用”在慕课网上线了,感谢小伙伴们学习支持!

我爱发短信:企业级短信平台定制开发专家 https://tonybai.com/
smspush : 可部署在企业内部的定制化短信平台,三网覆盖,不惧大并发接入,可定制扩展; 短信内容你来定,不再受约束, 接口丰富,支持长短信,签名可选。

著名云主机服务厂商DigitalOcean发布最新的主机计划,入门级Droplet配置升级为:1 core CPU、1G内存、25G高速SSD,价格5$/月。有使用DigitalOcean需求的朋友,可以打开这个链接地址:https://m.do.co/c/bff6eed92687 开启你的DO主机之路。

Gopher Daily(Gopher每日新闻)归档仓库 – https://github.com/bigwhite/gopherdaily

我的联系方式:

微博:https://weibo.com/bigwhite20xx
微信公众号:iamtonybai
博客:tonybai.com
github: https://github.com/bigwhite

微信赞赏:
img{512x368}

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言精进之路1 Go语言精进之路2 Go语言编程指南
商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats