Groovy 学习笔记3 运行效率

第一篇笔记里面,我说groovy运行的居然还满快的,其实是个误会了。我上次做八皇后还是在8080上面用basic做的,和现在奔四上面的groovy相比是没有意义的。特地又做了个对比试验:

 1int q=9
 2int[] i=new int[q]
 3int count=0
 4long t = System.currentTimeMillis();
 5scan(0)
 6println("totle results:"+count)
 7println("totle time:"+(System.currentTimeMillis()-t));
 8def scan(n){
 9    if (n==q){
10        println(i.toList())
11        count++
12        return
13    }

14    i[n]=0
15    while(i[n]<q){
16        i[n] = i[n]+1
17        if (check(n))
18            scan(n+1)
19    }

20}

21def check(n){
22    if (n>0)
23        for (j in 0..<n) 
24            if (i[j]==i[n] || i[j]-i[n]==j-|| i[j]-i[n]==n-j )
25                return false
26    return true
27}


运行结果是:totle time:7271 (为了用groovy控制台运行的,直接用groovy命令运行还要慢一点)

java呢?

queens.java:

 1public class queens {
 2    static int q=9;
 3    static int[] i=new int[q];
 4    static int count=0;
 5    public static void main(String[] args){
 6        long t = System.currentTimeMillis();
 7        scan(0);
 8        System.out.println("totle results:"+count);
 9        System.out.println("totle time:"+(System.currentTimeMillis()-t));
10    }

11    private static void scan(int n){
12        if (n==q){
13            for (int k=0;k<q;k++) System.out.print(i[k]+(k==q-1?"/n":","));
14            count++;
15            return;
16        }

17        i[n]=0;
18        while(i[n]<q){
19            i[n] = i[n]+1;
20            if (check(n)){
21                scan(n+1);
22            }

23        }

24    }

25    private static boolean check(int n){
26        for(int j=0;j<n;j++){
27            if (i[j]==i[n] || i[j]-i[n]==j-|| i[j]-i[n]==n-j ){
28                return false;
29            }

30        }

31        return true;
32    }

33}

34

运行结果是:totle time:271




每次运行花费的时间略有不同,groovy和java的运行速度看来大致相差10~30倍左右。


能说这是脚本语言天生的缺陷吗?我们来看看同样是类似java语法的脚本语言javascript在IE里面的速度:

 1var q=9 
 2var i=[] 
 3var count=0 
 4var d = new Date(); 
 5scan(0
 6document.write("totle results:"+count+"<br>"
 7document.write("time used:"+(new Date()-d)+"<br>"
 8
 9function scan(n)
10    if (n==q)
11        document.write(i+"<br>"
12        count++ 
13        return 
14    }
 
15    i[n]=0 
16    while(i[n]<q){
17        i[n] = i[n]+1 
18        if (check(n)){
19            scan(n+1
20        }
 
21    }
 
22}
 
23
24function check(n)
25    for (var j=0; j<n;j++)
26        if (i[j]==i[n] || i[j]-i[n]==j-|| i[j]-i[n]==n-j )
27            return false  
28    return true 
29}
 






运行结果是: time used:1241
比groovy快了5倍以上。groovy可真是够慢的。


把groovy编译的class文件反编译了一下,看到groovy生成的代码效率确实是太低了,我们就看循环最内层的check函数吧:


1def check(n){
2    if (n>0)
3        for (j in 0..<n) 
4            if (i[j]==i[n] || i[j]-i[n]==j-|| i[j]-i[n]==n-j )
5                return false
6    return true
7}


 


编译后变成



 1    public Object check(Object obj)
 2    {
 3        if(ScriptBytecodeAdapter.compareGreaterThan(obj, new Integer(0)))
 4        {
 5            Object obj1 = null;
 6            for(Iterator iterator = ScriptBytecodeAdapter.asIterator(ScriptBytecodeAdapter.createRange(new Integer(0), obj, false)); iterator.hasNext();)
 7            {
 8                Object obj2 = iterator.next();
 9                Object obj3 = null;
10                if(ScriptBytecodeAdapter.asBool(ScriptBytecodeAdapter.asBool(ScriptBytecodeAdapter.compareEqual(ScriptBytecodeAdapter.invokeMethod(ScriptBytecodeAdapter.getGroovyObjectProperty(this"i"), "getAt", ((Object) (new Object[] {
11    obj2
12}
))), ScriptBytecodeAdapter.invokeMethod(ScriptBytecodeAdapter.getGroovyObjectProperty(this"i"), "getAt", ((Object) (new Object[] {
13    obj
14}
)))) || ScriptBytecodeAdapter.compareEqual(ScriptBytecodeAdapter.invokeMethod(ScriptBytecodeAdapter.invokeMethod(ScriptBytecodeAdapter.getGroovyObjectProperty(this"i"), "getAt", ((Object) (new Object[] {
15    obj2
16}
))), "minus", ((Object) (new Object[] {
17    ScriptBytecodeAdapter.invokeMethod(ScriptBytecodeAdapter.getGroovyObjectProperty(this"i"), "getAt", ((Object) (new Object[] {
18        obj
19    }
)))
20}
))), ScriptBytecodeAdapter.invokeMethod(obj2, "minus", ((Object) (new Object[] {
21    obj
22}
)))) ? ((Object) (Boolean.TRUE)) : ((Object) (Boolean.FALSE))) || ScriptBytecodeAdapter.compareEqual(ScriptBytecodeAdapter.invokeMethod(ScriptBytecodeAdapter.invokeMethod(ScriptBytecodeAdapter.getGroovyObjectProperty(this"i"), "getAt", ((Object) (new Object[] {
23    obj2
24}
))), "minus", ((Object) (new Object[] {
25    ScriptBytecodeAdapter.invokeMethod(ScriptBytecodeAdapter.getGroovyObjectProperty(this"i"), "getAt", ((Object) (new Object[] {
26        obj
27    }
)))
28}
))), ScriptBytecodeAdapter.invokeMethod(obj, "minus", ((Object) (new Object[] {
29    obj2
30}
)))) ? ((Object) (Boolean.TRUE)) : ((Object) (Boolean.FALSE))))
31                    return Boolean.FALSE;
32            }

33
34        }

35        return Boolean.TRUE;
36    }

37




 

一切都是object,做任何事情都是invokeMethod,两个整数的比较居然要写将近400个字符的代码,光看代码量都可以吓倒我了。这是我们期待的脚本语言吗?


groovy可以嵌入到java代码里面,但是java代码可以嵌入到groovy里面吗?我觉得groovy有必要提供这样一种机制,在有必要的时候可以消除性能瓶颈。可是现在只看到groovy里面可以通过Scriptom(现在还是beta版)嵌入vbs、js脚本(包括使用WSH,FSO)或者调用InternetExplorer、Media Player、Word和Excel等windows组件。看来对消除性能瓶颈的帮助不大。

原文地址:https://www.cnblogs.com/stonehuang/p/6603237.html