Python/PHP/C/Go/Java运行时效率测试报告

August 04, 2016

Tags:trick

目录

前言

关于编程语言执行效率上经常会有纷争,尤其在一些技术社区上,新手或某一编程语言教的“信徒”吵得不可开交,即便是游走于多种编程语言的老手也很少会对不同的编程语言做效率方面的测试。
在这篇文章中,我们使用Linux著名的性能调查工具perf来对目前流行的几大编程语言(Python/PHP/C/Go/Java)做一次粗略的测试。网络上多数测试偏重于代码执行时间,例如使用time命令或
于代码中EndTime-StartTime的方式。本文我们会更关注于不同语言的“执行体”本身(我们姑且把虚拟机和解释型语言的Runtime环境+测试代码一同称作“执行体”),通过perf从kernel performance
计数器获取我们要对比的主要指标:task-clock、context-switches、instructions、time elapsed,关于这三个指标,这里做个简短的说明:

指标 含义
task-clock CPU 利用率,该值高,说明程序的多数时间花费在CPU计算上
context-switches 进程切换次数,记录了程序运行过程中发生了多少次进程切换,频繁的进程切换是应该避免的
instructions 执行的机器指令数目
time elapsed 执行总时长

测试脚本

for循环100次,在循环体内使用系统标准输出输出循环次数,例如:

for(int i=0;i<100;i++){
  printf("%d", i);
}

不同语言略有差异,可以自行修改发挥
测试命令(需要安装perf):

$perf stat ./perftest

Python

Version:
Python 2.7.11 (default, Jun 13 2016, 14:40:32)
Performance counter stats for 'python perftest.py':
     21.834121      task-clock (msec)         #    0.923 CPUs utilized          
           203      context-switches          #    0.009 M/sec                  
             0      cpu-migrations            #    0.000 K/sec                  
           819      page-faults               #    0.038 M/sec                  
    53,525,803      cycles                    #    2.451 GHz                      (72.71%)
    31,093,031      instructions              #    0.58  insn per cycle           (78.23%)
     7,452,040      branches                  #  341.302 M/sec                    (78.07%)
       455,057      branch-misses             #    6.11% of all branches          (74.22%)

   0.023647766 seconds time elapsed

PHP

Version:
PHP 5.6.24 (cli) (built: Jul 21 2016 06:00:05)
Performance counter stats for 'php perftest.php':
     22.209067      task-clock (msec)         #    0.937 CPUs utilized          
           102      context-switches          #    0.005 M/sec                  
             0      cpu-migrations            #    0.000 K/sec                  
         1,194      page-faults               #    0.054 M/sec                  
    56,005,669      cycles                    #    2.522 GHz                      (73.08%)
    39,328,607      instructions              #    0.70  insn per cycle           (72.92%)
     8,672,750      branches                  #  390.505 M/sec                    (77.65%)
       317,192      branch-misses             #    3.66% of all branches          (77.50%)

   0.023701000 seconds time elapsed

C

Verson:
gcc (GCC) 5.3.1 20160406 (Red Hat 5.3.1-6)
Performance counter stats for './cperftest':
      1.180835      task-clock (msec)         #    0.524 CPUs utilized          
             1      context-switches          #    0.847 K/sec                  
             0      cpu-migrations            #    0.000 K/sec                  
            48      page-faults               #    0.041 M/sec                  
       539,379      cycles                    #    0.457 GHz                    
       532,858      instructions              #    0.99  insn per cycle         
       106,361      branches                  #   90.073 M/sec                  
         7,819      branch-misses             #    7.35% of all branches          (41.63%)

    0.002252599 seconds time elapsed

Golang

Version:
go version go1.5.4 linux/amd64
Performance counter stats for './goperftest':
      5.707088      task-clock (msec)         #    0.851 CPUs utilized          
           253      context-switches          #    0.044 M/sec                  
             7      cpu-migrations            #    0.001 M/sec                  
           161      page-faults               #    0.028 M/sec                  
     6,068,679      cycles                    #    1.063 GHz                      (81.63%)
     2,727,919      instructions              #    0.45  insn per cycle           (83.70%)
       657,429      branches                  #  115.195 M/sec                    (79.66%)
        30,588      branch-misses             #    4.65% of all branches          (78.94%)

   0.006705245 seconds time elapsed

Java

Version:
openjdk version "1.8.0_101"OpenJDK Runtime Environment (build 1.8.0_101-b14)OpenJDK 64-Bit Server VM (build 25.101-b14, mixed mode)
Performance counter stats for 'java perftest':
    132.099235      task-clock (msec)         #    1.155 CPUs utilized          
           354      context-switches          #    0.003 M/sec                  
            39      cpu-migrations            #    0.295 K/sec                  
         2,387      page-faults               #    0.018 M/sec                  
   285,956,731      cycles                    #    2.165 GHz                      (76.09%)
   189,020,755      instructions              #    0.66  insn per cycle           (76.93%)
    36,100,532      branches                  #  273.283 M/sec                    (76.09%)
     2,142,873      branch-misses             #    5.94% of all branches          (74.80%)

   0.114330339 seconds time elapsed

结论

通过测试结果,我们可以获知这几种主流语言中,包括初始化阶段环境准备、加载、执行程序Java表现出难以接受的速度(虽然感官上可能体会不到);而C表现非常强劲,基本秒杀其他虚拟机语言和脚本语言。
Java执行效率不理想,可通过instructions得知,猜想Java虚拟机JVM要执行大量的指令,也可通过Task-Clock看出CPU使用情况,而Perf报告的1.155 CPUs utilized,也说明了此刻相比其他语言,CPU计算更为密集。
Python与PHP在计算时间开销上,相差不是很大,但与Go相比,还是有较大差距的。
Go与C相比,执行的指令会多出几倍数量级,但是相比Java不算什么。
这几种主流编程语言,从执行效率上看,投入产出比(代码行数/执行效率)高的编程语言非Go莫属?

补充

本次测试并未对数据结构、托管与非托管代码以及其他语言特性、垃圾收集做测试,如果有兴趣可以继续尝试下。
作者水平有限,欢迎大牛大神小牛小神们反馈建议(笑)

参考资料

Perf-Linux下的系统性能调优工具

· EOF ·