Groovy: закрытия значительно медленнее методов - PullRequest
5 голосов
/ 03 июля 2011

Играя с разными алгоритмами сортировки, я был удивлен, что Groovy-замыкания работали очень плохо.До сих пор я не мог найти хорошего ответа на этот вопрос, поэтому попытал счастья здесь;) Почему замыкания Groovy намного медленнее, чем традиционные методы?

Вот простой пример, показывающий разницу в производительности.Он создает два списка со случайными числами и сортирует их в обратном порядке, измеряя время сортировки.На моей машине и для элементов 10k это занимает 270 мс с использованием замыкания и только 50 мс с использованием реализации Comparator.

Время варьируется немного в зависимости от распределения случайных чисел.Также я попробовал 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}
}

Ответы [ 2 ]

4 голосов
/ 10 декабря 2012

Просто обновление с Groovy 2.0.5 с OpenJDK 1.6 (O6) и JDK 1.7 (J7) в Ubuntu.

Я также добавил две возможные реализации:

  • В качестве реализации 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
closure map                 258     499 146
one closure                 64      205 48
method                      29      37  32
@CompileStatic method       28      26  22

Обратите внимание, что у меня нет установленной командной строки Groovy, скомпилированной с JDK7 (та, которую я вытащил, автоматически устанавливает свой OpenJDK6), поэтому отсутствует соответствующий столбец.

4 голосов
/ 04 июля 2011

Что я могу сделать, чтобы улучшить производительность закрытия?

Подождите . JDK7 добавит новую инструкцию, известную как invokeDynamic , которая, как ожидается, радикально улучшит производительность динамических языков в JVM.

...