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次,重新更正相关测试的时间和部分结论。非常感谢装配脑袋的提醒。谢谢!另外对之前给大家的误导表示歉意!

  • 相关阅读:
    jQuery 语法
    jQuery 简介
    把数据存储到 XML 文件
    XML 注意事项
    XML DOM (Document Object Model) 定义了访问和操作 XML 文档的标准方法。
    通过 PHP 生成 XML
    XML 命名空间(XML Namespaces)
    XML to HTML
    XMLHttpRequest 对象
    使用 XSLT 显示 XML
  • 原文地址:https://www.cnblogs.com/BigTall/p/961711.html
Copyright © 2011-2022 走看看