Go/Python/Erlang编程语言对比分析及示例代码


Posted in Python onApril 23, 2018

本文主要是介绍Go,从语言对比分析的角度切入。之所以选择与Python、Erlang对比,是因为做为高级语言,它们语言特性上有较大的相似性,不过最主要的原因是这几个我比较熟悉。

Go的很多语言特性借鉴与它的三个祖先:C,Pascal和CSP。Go的语法、数据类型、控制流等继承于C,Go的包、面对对象等思想来源于Pascal分支,而Go最大的语言特色,基于管道通信的协程并发模型,则借鉴于CSP分支。

Go/Python/Erlang编程语言对比分析及示例代码

Go/Python/Erlang语言特性对比

 如《编程语言与范式》一文所说,不管语言如何层出不穷,所有语言的设计离不开2个基本面:控制流和数据类型。为了提升语言描述能力,语言一般都提供控制抽象和数据抽象。本小节的语言特性对比也从这4个维度入手,详见下图(点击见大图)。

图中我们可以看出,相比于Python的40个特性,Go只有31个,可以说Go在语言设计上是相当克制的。比如,它没有隐式的数值转换,没有构造函数和析构函数,没有运算符重载,没有默认参数,也没有继承,没有泛型,没有异常,没有宏,没有函数修饰,更没有线程局部存储。

但是Go的特点也很鲜明,比如,它拥有协程、自动垃圾回收、包管理系统、一等公民的函数、栈空间管理等。

Go作为静态类型语言,保证了Go在运行效率、内存用量、类型安全都要强于Python和Erlang。

Go的数据类型也更加丰富,除了支持表、字典等复杂的数据结构,还支持指针和接口类型,这是Python和Erlang所没有的。特别是接口类型特别强大,它提供了管理类型系统的手段。而指针类型提供了管理内存的手段,这让Go进入底层软件开发提供了强有力的支持。

Go在面对对象的特性支持上做了很多反思和取舍,它没有类、虚函数、继承、泛型等特性。Go语言中面向对象编程的核心是组合和方法(function)。组合很类似于C语言的struct结构体的组合方式,方法类似于Java的接口(Interface),但是使用方法上与对象更加解耦,减少了对对象内部的侵入。Erlang则不支持面对对象编程范式,相比而言,Python对面对对象范式的支持最为全面。

在函数式编程的特性支持上,Erlang作为函数式语言,支持最为全面。但是基本的函数式语言特性,如lambda、高阶函数、curry等,三种语言都支持。

控制流的特性支持上,三种语言都差不多。Erlang支持尾递归优化,这给它在函数式编程上带来便利。而Go在通过动态扩展协程栈的方式来支持深度递归调用。Python则在深度递归调用上经常被爆栈。

Go和Erlang的并发模型都来源于CSP,但是Erlang是基于actor和消息传递(mailbox)的并发实现,Go是基于goroutine和管道(channel)的并发实现。不管Erlang的actor还是Go的goroutine,都满足协程的特点:由编程语言实现和调度,切换在用户态完成,创建销毁开销很小。至于Python,其多线程的切换和调度是基于操作系统实现,而且因为GIL的大坑级存在,无法真正做到并行。

而且从笔者的并发编程体验上看,Erlang的函数式编程语法风格和其OTP behavior框架提供的晦涩的回调(callback)使用方法,对大部分的程序员,如C/C++和Java出身的程序员来说,有一定的入门门槛和挑战。而被称为“互联网时代的C”的Go,其类C的语法和控制流,以及面对对象的编程范式,编程体验则好很多。

Go/Python/Erlang编程语言对比分析及示例代码

Go/Python/Erlang语言语法对比

所有的语言特性都需要有形式化的表示方式,Go、Python、Erlang三种语言语法的详细对比如下(点击见完整大图第一部分,第二部分,第三部分)。这里(链接)有一个详细的Go 与 C 的语法对比,这也是我没有做Go vs. C对比的一个原因。

正如Go语言的设计者之一Rob Pike所说,“软件的复杂性是乘法级相关的”。这充分体现在语言关键词(keyword)数量的控制上,Go的关键词是最少的,只有25个,而Erlang是27个,Python是31个。从根本上保证了Go语言的简单易学。

Go语言将数据类型分为四类:基础类型、复合类型、引用类型和接口类型。基础类型包括:整型、浮点型、复数、字符串和布尔型。复合数据类型有数组和结构体。引用类型包括指针、切片、字典、函数、通道。其他数据类型,如原子(atom)、比特(binary)、元组(tuple)、集合(set)、记录(record),Go则没有支持。

Go对C语言的很多语法特性做了改良,正如Rob Pike在《Less is Exponentially More》中提到,Go的“起点: C语言,解决一些明显的瑕疵、删除杂质、增加一些缺少的特性。”,比如,switch/case的case子程序段默认break跳出,case语句支持数值范围、条件判断语句;所有类型默认初始化为0,没有未初始化变量;把类型放在变量后面的声明语法(链接),使复杂声明更加清晰易懂;没有头文件,文件的编译以包组织,改善封装能力;用空接口(interface {})代替void *,提高类型系统能力等等。

Go对函数,方法,接口做了清晰的区分。与Erlang类似,Go的函数作为第一公民。函数可以让我们将一个语句序列打包为一个单元,然后可以从程序中其它地方多次调用。函数和方法的区别是指有没有接收器,而不像其他语言那样是指有没有返回值。接口类型具体描述了一系列方法的集合,而空接口interfac{}表示可以接收任意类型。接口的这2中使用方式,用面对对象编程范式来类比的话,可以类比于subtype polymorphism(子类型多态)和ad hoc polymorphism(非参数多态)。

从图中示例可以看出,Go的goroutine就是一个函数,以及在堆上为其分配的一个堆栈。所以其系统开销很小,可以轻松的创建上万个goroutine,并且它们并不是被操作系统所调度执行。goroutine只能使用channel来发送给指定的goroutine请求来查询更新变量。这也就是Go的口头禅“不要使用共享数据来通信,使用通信来共享数据”。channel支持容量限制和range迭代器。

Go/Python/Erlang编程语言对比分析及示例代码Go/Python/Erlang编程语言对比分析及示例代码Go/Python/Erlang编程语言对比分析及示例代码

Go/Python/Erlang语言词法对比

Go、Python、Erlang三种语言词法符号的详细对比如下(点击见完整大图)。Go的词法符号是3个语言中最多的,有41个,而且符号复用的情况也较多。相对来说,Python最少,只有31个。

Go语言在词法和代码格式上采取了很强硬的态度。Go语言只有一种控制可见性的手段:大写首字母的标识符会从定义它们的包中被导出,小写字母的则不会。这种限制包内成员的方式同样适用于struct或者一个类型的方法。

在文件命名上,Go也有一定的规范要求,如以_test.go为后缀名的源文件是测试文件,它们是go test测试的一部分;测试文件中以Test为函数名前缀的函数是测试函数,用于测试程序的一些逻辑行为是否正确;以Benchmark为函数名前缀的函数是基准测试函数,它们用于衡量一些函数的性能。

除了关键字,此外,Go还有大约30多个预定义的名字,比如int和true等,主要对应内建的常量、类型和函数。

Go/Python/Erlang编程语言对比分析及示例代码

TDD Go编程示例

本小节以TDD方式4次重构开发一个斐波那契算法的方式,来简单展示Go的特性、语法和使用方式,如Go的单元测试技术,并发编程、匿名函数、闭包等。

首先,看一下TDD最终形成的单元测试文件:

package main
import (
  "testing"
)
func TestFib(t *testing.T) {
  var testdatas = []struct {
    n  int
    want int64
  }{
    {0, 0},
    {1, 1},
    {2, 1},
    {3, 2},
    {4, 3},
    {16, 987},
    {32, 2178309},
    {45, 1134903170},
  }
  for _, test := range testdatas {
    n := test.n
    want := test.want
    got := fib(n)
    if got != want {
      t.Errorf("fib(%d)=%d, want %d\n", n, got, want)
    }
  }
}

基于递归的实现方案:

func fib1(n int) int64 {
  if n == 0 || n == 1 {
    return int64(n)
  }
  return fib1(n-1) + fib1(n-2)
}

测试结果:

crbsp@fib$ time go test
PASS
ok _/home/crbsp/alex/go/fib 9.705s
real 0m10.045s
user 0m9.968s
sys 0m0.068s

基于goroutine实现的并发方案:

func fib2(n int) int64 {
  var got int64
  var channel = make(chan int64, 2)
  if n == 0 || n == 1 {
    return int64(n)
  }
  runtime.GOMAXPROCS(2)
  go func() { channel <- fib1(n - 2) }()
  go func() { channel <- fib1(n - 1) }()
  got = <-channel
  got += <-channel
  return got
}

测试结果:

crbsp@fib$ time go test
PASS
ok _/home/crbsp/alex/go/fib 6.118s
real 0m6.674s
user 0m10.268s
sys 0m0.148s

基于迭代的实现方案:

func fib3(n int) int64 {
  var a, b int64
  a, b = 0, 1
  for i := 0; i < n; i++ {
    a, b = b, a+b
  }
  return a
}

测试结果:

crbsp@fib$ time go test
PASS
ok _/home/crbsp/alex/go/fib 0.002s
real 0m0.547s
user 0m0.328s
sys 0m0.172s

基于闭包的实现方案:

func fibWrapper4() func() int64 {
  var a, b int64
  a, b = 0, 1
  return func() int64 {
    a, b = b, a+b
    return a
  }
}
func fib4(n int) int64 {
  var got int64
  got = 0
  f := fibWrapper4()
  for i := 0; i < n; i++ {
    got = f()
  }
  return got
}

测试结果:

crbsp@fib$ time go test
PAok _/home/crbsp/alex/go/fib 0.002s
real 0m0.411s
user 0m0.260s
sys 0m0.140s

总结

以上所述是小编给大家介绍的Go/Python/Erlang编程语言对比分析及示例代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Python 相关文章推荐
python远程登录代码
Apr 29 Python
python 图片验证码代码
Dec 07 Python
Django中使用group_by的方法
May 26 Python
Python首次安装后运行报错(0xc000007b)的解决方法
Oct 18 Python
python下os模块强大的重命名方法renames详解
Mar 07 Python
Python 中开发pattern的string模板(template) 实例详解
Apr 01 Python
Pandas中resample方法详解
Jul 02 Python
Django forms表单 select下拉框的传值实例
Jul 19 Python
解决python3 安装不了PIL的问题
Aug 16 Python
Python上下文管理器类和上下文管理器装饰器contextmanager用法实例分析
Nov 07 Python
Python约瑟夫生者死者小游戏实例讲解
Jan 04 Python
python分分钟绘制精美地图海报
Feb 15 Python
Python 3.6 读取并操作文件内容的实例
Apr 23 #Python
Python 循环语句之 while,for语句详解
Apr 23 #Python
下载python中Crypto库报错:ModuleNotFoundError: No module named ‘Crypto’的解决
Apr 23 #Python
python批量替换多文件字符串问题详解
Apr 22 #Python
Diango + uwsgi + nginx项目部署的全过程(可外网访问)
Apr 22 #Python
Python3.6笔记之将程序运行结果输出到文件的方法
Apr 22 #Python
Python解决八皇后问题示例
Apr 22 #Python
You might like
syphon 虹吸式咖啡冲泡冲煮倒水的得与失
2021/03/03 冲泡冲煮
提高PHP编程效率的53个要点(经验小结)
2010/09/04 PHP
通过php删除xml文档内容的方法
2015/01/23 PHP
PHP大文件分块上传功能实例详解
2019/07/22 PHP
PHP实现的文件浏览器功能简单示例
2019/09/12 PHP
jQuery使用手册之三 CSS操作
2007/03/24 Javascript
纯JavaScript实现的完美渐变弹出层效果代码
2010/04/02 Javascript
jQuery实现带玻璃流光质感的手风琴特效
2015/11/20 Javascript
js输出数据精确到小数点后n位代码
2016/07/02 Javascript
bootstrap laydate日期组件使用详解
2017/01/04 Javascript
Vue 短信验证码组件开发详解
2017/02/14 Javascript
js通过keyCode值判断单击键盘上某个键,然后触发指定的事件方法
2017/02/19 Javascript
Vuex中mutations与actions的区别详解
2018/03/01 Javascript
JS实现调用本地摄像头功能示例
2018/05/18 Javascript
谈谈JavaScript中super(props)的重要性
2019/02/12 Javascript
浅谈Javascript常用正则表达式应用
2019/03/08 Javascript
原生js实现二级联动菜单
2019/11/27 Javascript
bootstrap-paginator服务器端分页使用方法详解
2020/02/13 Javascript
jQuery 选择方法及$(this)用法实例分析
2020/05/19 jQuery
Vue 实现监听窗口关闭事件,并在窗口关闭前发送请求
2020/09/01 Javascript
我所理解的JavaScript中的this指向
2020/09/04 Javascript
ES11屡试不爽的新特性,你用上了几个
2020/10/21 Javascript
Python中使用 Selenium 实现网页截图实例
2014/07/18 Python
Python实现九宫格式的朋友圈功能内附“马云”朋友圈
2019/05/07 Python
python 类的继承 实例方法.静态方法.类方法的代码解析
2019/08/23 Python
Window10下python3.7 安装与卸载教程图解
2019/09/30 Python
详解python tcp编程
2020/08/24 Python
利用python绘制正态分布曲线
2021/01/04 Python
详解如何用canvas画一个微笑的表情
2019/03/14 HTML / CSS
英国时尚优质的女装:Hope Fashion
2018/08/14 全球购物
5个HTML5的常用本地存储方式详解与介绍
2021/03/27 HTML / CSS
出纳担保书范文
2014/04/02 职场文书
个人查摆剖析材料
2014/10/04 职场文书
2015教师节通讯稿
2015/07/20 职场文书
《坐井观天》教学反思
2016/02/18 职场文书
MySQL 重写查询语句的三种策略
2021/05/10 MySQL