服务器之家

服务器之家 > 正文

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

时间:2021-02-04 00:38     来源/作者:Write the code, change the wor

本文主要是介绍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最终形成的单元测试文件:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main
import (
  "testing"
)
func testfib(t *testing.t) {
  var testdatas = []struct {
    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)
    }
  }
}

基于递归的实现方案:

?
1
2
3
4
5
6
func fib1(n int) int64 {
  if n == 0 || n == 1 {
    return int64(n)
  }
  return fib1(n-1) + fib1(n-2)
}

测试结果:

?
1
2
3
4
5
6
crbsp@fib$ time go test
pass
ok _/home/crbsp/alex/go/fib 9.705s
real 0m10.045s
user 0m9.968s
sys 0m0.068s

基于goroutine实现的并发方案:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
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

基于迭代的实现方案:

?
1
2
3
4
5
6
7
8
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

基于闭包的实现方案:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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编程语言对比分析及示例代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对服务器之家网站的支持!

原文链接:https://www.cnblogs.com/wahaha02/p/8876445.html

相关文章

热门资讯

2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全 2019-12-26
Intellij idea2020永久破解,亲测可用!!!
Intellij idea2020永久破解,亲测可用!!! 2020-07-29
背刺什么意思 网络词语背刺是什么梗
背刺什么意思 网络词语背刺是什么梗 2020-05-22
yue是什么意思 网络流行语yue了是什么梗
yue是什么意思 网络流行语yue了是什么梗 2020-10-11
苹果12mini价格表官网报价 iPhone12mini全版本价格汇总
苹果12mini价格表官网报价 iPhone12mini全版本价格汇总 2020-11-13
返回顶部