Groovy:闭包比方法慢得多?

6
在使用不同的排序算法时,我惊讶地发现Groovy闭包的性能非常差。到目前为止,我还没有找到一个好的答案,所以现在在这里尝试一下;)为什么Groovy闭包比传统方法慢得多?
以下是一个简单的例子,显示了性能差异。它创建了两个带有随机数字的列表,并按相反顺序对它们进行排序,测量排序时间。在我的机器上,对于10k个元素,使用闭包需要270毫秒,而使用Comparator实现只需要50毫秒。
根据随机数的分布,计时会有些变化。此外,我尝试过Groovy 1.7.4和1.8.0,在后者中性能略有提高。但总体情况保持不变:闭包的性能很差。
除了不使用闭包之外,我该怎么做来提高闭包的性能呢?我是否遗漏了什么,或者在Groovy中如果性能很重要就不应该使用闭包?
def numberCount = 10000
def random = new Random()
def unorderedList1 = (1..numberCount).collect{random.nextInt()}
def unorderedList2 = (1..numberCount).collect{random.nextInt()}
def timeit = {String message, Closure cl->
    def startTime = System.currentTimeMillis()
    cl()
    def deltaTime = System.currentTimeMillis() - startTime
    println "$message: \ttime: $deltaTime"
}

timeit("compare using closure") {
    def comparator= [ compare: { a,b -> return b <=> a }] as Comparator
    unorderedList1.sort(comparator)
}

timeit("compare using method") {
    Comparator comparator = new MyComparator()
    unorderedList2.sort(comparator)
}

class MyComparator implements Comparator {
    int compare(a, b) {return b <=> a}
}

1
270毫秒与50毫秒对我来说并没有太大的差异。如果您想看到一些聪明的Groovy用法,其中它比Java或C++实现更快(不是故意挑衅,请先观看视频),请查看此处:http://www.infoq.com/presentations/Groovy-Best-Practices - SteveD
2个回答

5

更新一下,在Ubuntu上使用Groovy 2.0.5和OpenJDK 1.6(O6)以及JDK 1.7(J7)。

我还添加了两种可能的实现:

  • only one closure provided as the implementation of Comparator:
  • a method annotated with @CompileStatic:

    def numberCount = 10000
    def random = new Random()
    def unorderedList1 = (1..numberCount).collect{random.nextInt()}
    def unorderedList2 = (1..numberCount).collect{random.nextInt()}
    def unorderedList3 = (1..numberCount).collect{random.nextInt()}
    def unorderedList4 = (1..numberCount).collect{random.nextInt()}
    def timeit = {String message, Closure cl->
        def startTime = System.currentTimeMillis()
        cl()
        def deltaTime = System.currentTimeMillis() - startTime
        println "$message: \ttime: $deltaTime"
    }
    
    timeit("compare using map of closures") {
        def comparator= [ compare: { a,b -> return b <=> a }] as Comparator
        unorderedList1.sort(comparator)
    }
    
    timeit("compare using one closure") {
        def comparator= { a, b -> return b <=> a } as Comparator
        unorderedList2.sort(comparator)
    }
    
    timeit("compare using method") {
        Comparator comparator = new MyComparator()
        unorderedList3.sort(comparator)
    }
    
    timeit("compare using method with @CompileStatic") {
        Comparator comparator = new MyComparator2()
        unorderedList4.sort(comparator)
    }
    
    class MyComparator implements Comparator {
        int compare(a, b) {return b <=> a}
    }
    
    class MyComparator2 implements Comparator<Integer> {
        @groovy.transform.CompileStatic
        int compare(Integer a, Integer b) {return b <=> a}
    }
    
Groovy 2.0.5                groovy  groovyc 
                            O6      O6  J7
闭包映射                    258     499 146
单个闭包                   64      205 48
方法                        29      37  32
@CompileStatic 方法         28      26  22

请注意,我没有安装使用JDK7编译的Groovy命令行(自动安装的是其自己的OpenJDK6),因此缺少相应的列。


4

如何提高闭包性能?

等待。JDK7将会增加一个新的指令,即invokeDynamic,预计将极大地改善JVM上动态语言的性能。


是的,Don 是正确的 :) 你也可以查看这个链接以了解更多信息 :D http://java.sun.com/developer/technicalArticles/DynTypeLang/index.html - Ant's
3
关于 def comparator = [ compare: { a, b -> return b <=> a }] as Comparator 的工作原理,它返回一个代理类,该类扩展了java.lang.reflect.Proxy,并具有与 Comparator 相同的签名。这意味着对 comparator 对象进行任何调用都将是间接的,因此需要更长的时间。为了对列表进行排序,会大约调用这个 Proxy 对象 120000 次,因此在运行时间上会有所差异。 - tim_yates
@tim_yates - 这更像是对问题的回答。 - Victor Sergienko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接