【问题标题】:Groovy : closures significantly slower than methods?Groovy:闭包比方法慢得多?
【发布时间】:2011-09-27 14:27:38
【问题描述】:

在使用不同的排序算法时,我很惊讶 Groovy 闭包的性能非常差。到目前为止我还没有找到一个好的答案,所以现在试试我的运气;)为什么 Groovy 闭包比传统方法慢这么多?

这是一个显示性能差异的简单示例。它创建两个带有随机数的列表,并以相反的顺序对它们进行排序,测量排序时间。在我的机器上,对于 10k 个元素,使用闭包需要 270ms,而使用 Comparator 实现只需要 50ms

时间会根据随机数的分布而有所不同。我还尝试了 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}
}

【问题讨论】:

  • 270ms v 50ms 对我来说并不属于差异的“数量级”。如果你想看看 Groovy 的一些巧妙使用,它最终比 Java 或 C++ 实现更快(不是作为诱饵:先看视频),看这里:infoq.com/presentations/Groovy-Best-Practices

标签: performance groovy closures


【解决方案1】:

我可以做些什么来提高关闭性能?

等待。 JDK7 将添加一条新指令,称为invokeDynamic,有望从根本上提高 JVM 上动态语言的性能。

【讨论】:

  • 是的,唐是对的 :) 您也可以查看此链接以了解更多信息:D java.sun.com/developer/technicalArticles/DynTypeLang/index.html
  • 作为关于def comparator= [ compare: { a,b -&gt; return b &lt;=&gt; a }] as Comparator 工作原理的快速说明,它返回一个扩展java.lang.reflect.Proxy 的代理类,并具有与Comparator 相同的签名。这意味着任何调用comparator 对象的调用都是间接的,因此需要更长的时间。为了对列表进行排序,这个Proxy 对象被调用了大约120000 次,因此在时间上有所不同。
  • @tim_yates - 这更像是对问题的回答。
【解决方案2】:

只是在 Ubuntu 上使用带有 OpenJDK 1.6 (O6) 和 JDK 1.7 (J7) 的 Groovy 2.0.5 进行了更新。

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

  • 仅提供一个闭包作为 Comparator 的实现:
  • 用@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),因此缺少相应的列。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-22
    • 2011-10-27
    • 1970-01-01
    相关资源
    最近更新 更多