网络上python和ruby之间的口水战从来都没有停止过。有人说python慢,有人说ruby更慢;有人说python美,有人说ruby更美。究竟怎样呢?
我们不搞大而全的测评,就从简单的N皇后问题求方法数的暴力搜索程序中窥探一下吧:
下面是代码:
1 N=13 2 col=[0]*N 3 d1=[0]*(N*2) 4 d2=[0]*(N*2) 5 ret=0 6 def dfs(x): 7 global ret 8 if x==N: 9 ret+=1 10 else: 11 for i in xrange(N): 12 if col[i]==0 and d1[i+x]==0 and d2[i-x+N]==0: 13 col[i],d1[i+x],d2[i-x+N]=1,1,1 14 dfs(x+1) 15 col[i],d1[i+x],d2[i-x+N]=0,0,0 16 dfs(0) 17 print ret
根据python代码,我改编了各个语言的版本:
1 N=13 2 $col=[0]*N 3 $d1=[0]*(N*2) 4 $d2=[0]*(N*2) 5 $ret=0 6 def dfs(x) 7 if x==N 8 $ret+=1 9 else 10 N.times do |i| 11 if $col[i]==0 and $d1[i+x]==0 and $d2[i-x+N]==0 12 $col[i]=$d1[i+x]=$d2[i-x+N]=1 13 dfs x+1 14 $col[i]=$d1[i+x]=$d2[i-x+N]=0 15 end 16 end 17 end 18 end 19 dfs 0 20 puts $ret
1 #include <cstdio> 2 using namespace std; 3 const int N=13; 4 int col[N],d1[N+N],d2[N+N]; 5 int ret=0; 6 void dfs(int x){ 7 if (x==N) 8 ret++; 9 else{ 10 for (int i=0;i<N;i++) 11 if (col[i]==0 && d1[i+x]==0 && d2[i-x+N]==0){ 12 col[i]=d1[i+x]=d2[i-x+N]=1; 13 dfs(x+1); 14 col[i]=d1[i+x]=d2[i-x+N]=0; 15 } 16 } 17 } 18 int main() 19 { 20 dfs(0); 21 printf("%d\n",ret); 22 return 0; 23 }
1 package main 2 import "fmt" 3 const N=13 4 var col [N]int 5 var d1,d2 [N*2]int 6 var ret int 7 func dfs(x int){ 8 if x==N{ 9 ret++ 10 }else{ 11 for i:=0;i<N;i++ { 12 if col[i]==0 && d1[i+x]==0 && d2[i-x+N]==0 { 13 col[i],d1[i+x],d2[i-x+N]=1,1,1 14 dfs(x+1) 15 col[i],d1[i+x],d2[i-x+N]=0,0,0 16 } 17 } 18 } 19 } 20 func main(){ 21 dfs(0) 22 fmt.Println(ret) 23 }
下面是代码长度的比较:
268 a.py
273 a.rb
333 a.go
356 a.cpp
可以看出,python是最短的,而ruby其实在某些地方上写的更短(例如省略了小括号和冒号),但是倒霉的$和end的使用让它的代码长度激增。python的缩进政策一方面简化了end的输入,另一方面也强制程序员写出优雅的代码。不过我至今也想不明白为什么python非要有那个冒号不可。
N.times do |i| if $col[i]==0 and $d1[i+x]==0 and $d2[i-x+N]==0 $col[i]=$d1[i+x]=$d2[i-x+N]=1 dfs x+1 $col[i]=$d1[i+x]=$d2[i-x+N]=0 end end
for i in xrange(N): if col[i]==0 and d1[i+x]==0 and d2[i-x+N]==0: col[i],d1[i+x],d2[i-x+N]=1,1,1 dfs(x+1) col[i],d1[i+x],d2[i-x+N]=0,0,0
go和cpp也是难分长短的。go在函数的主要逻辑的部分几乎和脚本语言一样,
func dfs(x int){ if x==N{ ret++ }else{ for i:=0;i<N;i++ { if col[i]==0 && d1[i+x]==0 && d2[i-x+N]==0 { col[i],d1[i+x],d2[i-x+N]=1,1,1 dfs(x+1) col[i],d1[i+x],d2[i-x+N]=0,0,0 } } } }
除了那个煞风景的int,我们很难把他称作是静态类型的编译执行语言。
但go的问题和cpp一样,那就是,为了让一个程序运行你不得不说很多“废话”。
package main import "fmt" #include <cstdio> using namespace std;
然后就是大家十分关心的运行效率了
我time了一下:
python 0m6.944s
ruby 0m6.728s
C(C++) 0m0.360s
go 0m0.320s
这个结果出乎很多人的预料,go竟然可以跑的比c++还快,而python和ruby之间也没有想象中的性能差距。
当然了,python有一个加速方法,就是使用pypy,而C++也可以开-O2,我们看看效果:
pypy 0m0.908s
C(C++)-O2 0m0.236s
可以看出,增强版的python和go还是领先他们的对手一大截的。
而go为了编译效率,不强调编译优化的使用。ruby也有jit工具,不过我还没有进行测试。
做个总结吧,python和ruby实在是难分高下,更多的是个人的口味问题。
就像唯物主义者和唯心主义者永远不可能在物质是否决定意识上达成一致一样,python和ruby的使用者也很难说服对方转换阵营。更多的争吵其实只是浪费能量。
如果你不在乎20倍左右的运行时间的差异,那么脚本语言是你的不二选择,因为他能够换取你的编码时间。