zoukankan      html  css  js  c++  java
  • JScript.net的运行效率测试(兼多种语言效率对比)

    昨天的文章《用JScript.net写.net应用程序》一文写了之后,对于其运行效率问题有了一点疑问,所以需要进行以下测试,前人当然做过很多种测试,不过bigtall的测试方法有些不同。这里我采用了斐波纳契的两个算法,一个是递归实现,一个是迭代实现。采用斐波纳契的理由如下:

    1. 它是一个复杂度为O(2n)的算法,计算量足够大
    2. 相同的计算,递归和迭代的主要区别是堆栈的处理,我们也可以同时比较一下不同语言在调用函数之间的效率差别。
    3. 代码简单,而且算法容易理解。不同测试代码之间的差别也小,不容易起争议。

    测试运行时候考虑到如下的情况:

    1. 第一次系统装入是从磁盘装入,而后几次则是直接从磁盘缓存装入,所每个测试连续运行4遍,第一遍时间不计入。
    2. 因为IO库实现效率不同,所以算法代码中不存在任何IO调用,纯计算代码。

    参与比较的语言包括c,c#,标准的javascript,JScript.net,后来觉得不过瘾,把java6也加上了。加上bigtall自己写的一个计算时间的小程序和批处理,一共12段代码,表示如下:

    fibc.c fib2c.c

    long Fib(long n)
    {
        if (n <= 1) {
            return n;
        } else {
            return Fib(n - 1) + Fib(n - 2);
        }
    }

    void main()
    {
        int i;
        for(i = 0; i < 10; i++)
            Fib(30);
    }

    long Fib(long n)
    {
        int i;
        long a = 0, b = 1, c=0;
        if (n <= 1) {
            return n;
        } else {
            for (i = 2; i <= n; i++) {
                c = a + b;
                a = b;
                b = c;
            }
            return c;
        }
    }

    void main()
    {
        int i;
        for(i = 0; i < 26925370; i++)
            Fib(30);
    }

    fibcs.cs fib2cs.cs

    public class A
    {
    static long Fib(long n)
    {
        if (n <= 1) {
            return n;
        } else {
            return Fib(n - 1) + Fib(n - 2);
        }
    }

    public static void Main()
    {
        for(int i = 0; i < 10; i++)
            Fib(30);
    }

    }

    public class A
    {
    static long Fib(long n)
    {
        int i;
        long a = 0, b = 1, c=0;
        if (n <= 1) {
            return n;
        } else {
            for (i = 2; i <= n; i++) {
                c = a + b;
                a = b;
                b = c;
            }
            return c;
        }
    }

    public static void Main()
    {
        for(int i = 0; i < 26925370; i++)
            Fib(30);
    }

    }

    fibjava.java fib2java.java

    public class fibjava
    {
    static long Fib(long n)
    {
        if (n <= 1) {
            return n;
        } else {
            return Fib(n - 1) + Fib(n - 2);
        }
    }

    public static void main(String[] args)
    {
        for(int i = 0; i < 10; i++)
            Fib(30);
    }

    }

    public class fib2java
    {
    static long Fib(long n)
    {
        int i;
        long a = 0, b = 1, c=0;
        if (n <= 1) {
            return n;
        } else {
            for (i = 2; i <= n; i++) {
                c = a + b;
                a = b;
                b = c;
            }
            return c;
        }
    }

    public static void main(String[] args)
    {
        for(int i = 0; i < 26925370; i++)
            Fib(30);
    }

    }

    fibjs1.js fib2js1.js

    function Fib(n)
    {
        if (n <= 1) {
            return n;
        } else {
            return Fib(n - 1) + Fib(n - 2);
        }
    }

    for(var i:int = 0; i < 10; i++)
        Fib(30);

    function Fib(n)
    {
        var i;
        var a = 0, b = 1, c=0;
        if (n <= 1) {
            return n;
        } else {
            for (i = 2; i <= n; i++) {
                c = a + b;
                a = b;
                b = c;
            }
            return c;
        }
    }

    for(var i:int = 0; i < 26925370; i++)
        Fib(30);

    fibjs2.js fib2js2.js

    function Fib(n:int):int
    {
        if (n <= 1) {
            return n;
        } else {
            return Fib(n - 1) + Fib(n - 2);
        }
    }

    for(var i:int = 0; i < 10; i++)
        Fib(30);

    function Fib(n:int):int
    {
        var i:int;
        var a:int = 0, b:int = 1, c:int=0;
        if (n <= 1) {
            return n;
        } else {
            for (i = 2; i <= n; i++) {
                c = a + b;
                a = b;
                b = c;
            }
            return c;
        }
    }

    for(var i:int = 0; i < 26925370; i++)
        Fib(30);

    ptime.cs cp.bat

    public class A
    {
        public static void Main()
        {
            System.Console.Write(System.DateTime.Now.Ticks);
            System.Console.Write(',');
        }

    }

    @echo off
    cl /O2 fibc.c
    cl /O2 fib2c.c

    csc /o+ /debug- fibcs.cs
    csc /o+ /debug- fib2cs.cs

    jsc /fast- /debug- fibjs1.js
    jsc /fast- /debug- fib2js1.js

    jsc /fast+ /debug- fibjs2.js
    jsc /fast+ /debug- fib2js2.js

    "%JAVA_HOME%\bin\javac" -g:none fibjava.java
    "%JAVA_HOME%\bin\javac" -g:none fib2java.java

    echo 编译完成

    call:run fibc
    call:run fib2c
    call:run fibcs
    call:run fib2cs
    call:run fibjs1
    call:run fib2js1
    call:run fibjs2
    call:run fib2js2
    call:run "%JAVA_HOME%\bin\java" fibjava
    call:run "%JAVA_HOME%\bin\java" fib2java
    echo finish!

    goto end
    :run
    echo =================================
    ptime & %1 %2 & ptime & echo %1 %2 1
    ptime & %1 %2 & ptime & echo %1 %2 2
    ptime & %1 %2 & ptime & echo %1 %2 3
    ptime & %1 %2 & ptime & echo %1 %2 4

    :end

    运行测试的结果如下表格所示,表格内部蓝色的4组数据分别为1,2,3,4测试数据,黑色数据为后三组测试结果的平均数,绿色数据为相对C语言运行耗时的比例,最后一行红色纵比数字为相同语言【单次】递归和迭代算法的耗时比例。时间单位为百分之一秒:

     

    C

    C#

    java

    js

    JScript.net

    递归
    (10次)

    119
    49
    48
    49

    486
    439
    461
    441

    2258
    520
    467
    464

    75397
    75327
    76424
    74228

    1571
    1501
    1502
    1499

    48.67

    447

    483.67

    75326.33

    1500.67

    1

    9.18

    9.94

    1547.70

    30.83

    迭代
    (26,925,370次)

    120
    49
    47
    46

    5261
    5041
    5040
    5039

    7880
    7769
    7762
    7766

    125786
    127117
    127273
    127541

    9196
    9101
    9086
    9121

    47.33

    5040

    7765.67

    127310.33

    9102.67

    1

    106.48

    164.06

    2689.65

    192.31

    纵比 0.97 11.28 16.06 1.69 6.07

    由此,我们看出,如果横向比较,以C语言运行速度为标准,递归运算的时候,C#和java的速度都慢了将近10倍,JScript.net慢了将近31倍,js因为使用了运行时绑定,速度慢了1500倍之多;而一旦消除了函数调用,使用纯计算代码的迭代算法的运行时间上,各种语言相差更大,而且明显C#代码比java快(这里没有考虑基础类库装入的差别,因为M$对.net有预装入),最差的依然是javascript,不过看起来不带调用的后期绑定似乎更快一些。不过令人惊讶的是JScript.net的编译优化做的不错,速度算是很快了。

    纵向比较之前,我们需要对算法进行一下分析,通过简单的代码,我们得知fib(30)的递归调用次数为2692537次,10次重复就是26925370次。这个就是递归和迭代算法的区别所在,但是我们把迭代的次数也设定为26925370,以消除函数调用的差别,突出代码的线性运行差别。通过对代码的分析,我们得出代码特征的统计表格:

      递归 迭代
    赋值语句 3 120
    变量分配 2 4
    函数调用 2 0
    返回 2 2
    条件判断 1 30
    跳转 1 30
    累计 11 186

    迭代算法和递归算法相比,明显代码量较大,其代码规模大约是递归的186/11=16.9倍。但是运行时间中除了java体现出了这一比例之外,其他都比这个比例要小。C语言甚至时间更短,如果不考虑测试误差,唯一合理的解释应该是代码优化问题,因为编译器和CPU都有优化代码的能力,但是显然无论是哪种优化,都无法跨越函数调用进行优化;C#比java要快,是不是说明C#的优化器比java要好一些呢?但是JS代码的两个比例值有点让我难住了,但是也并非不可解释,因为js代码中间可以优化的地方实在是太多太多了。

    结论:

    1. C作为一种老牌的中高级语言,优势没得说。
    2. 递归少用,尤其是JavaScript,连函数调用都尽可能压缩一些。
    3. 本文的最主要目的,如果用JScript.net做一般应用程序,效率应该属于可以接受的范围,但是千万不要进行数值计算。
    4. 以前看过什么java或者C#运行效率可以达到C语言的70%之类的文章,现在看来是有水分的,如果单纯比较编译器的效率,我看差距还是明显的。看来枪手文章还是要警惕啊!

    另外给各位看官提一个小小的请求,如果哪位对python,ruby,perl等熟悉的,用相同算法做一个测试如何?

    本文章算法参考了浅议Fibonacci(斐波纳契)数列求解

    ========================================

    2007-11-16 17:30修改迭代部分的循环次数为26925370次,重新更正相关测试的时间和部分结论。非常感谢装配脑袋的提醒。谢谢!另外对之前给大家的误导表示歉意!

  • 相关阅读:
    spark简单入门
    vim 树形目录插件NERDTree
    Windows下查看系统端口使用的命令
    网络爬虫爬取动态网页
    Java并查集链表实现
    基于mahout的海量数据关联规则挖掘
    高维特征降维方法-随机映射
    JVM(4)--垃圾回收算法
    Java高并发程序设计(六)--线程池(1)
    Java高并发程序设计(五)--ReentrantLock源码解析
  • 原文地址:https://www.cnblogs.com/BigTall/p/961711.html
Copyright © 2011-2022 走看看