Защо която и да е програма на Java/Clojure се забавя, когато се изпълнява от Leiningen?

Докато сравнявах приложение на Clojure и се опитвах да установя проблеми с производителността, забелязах това странно поведение: дори когато цялата програма е написана на Java, когато се стартира от Leiningen, изглежда, че изпитва значително забавяне.

Да кажем, че имам тази Java програма:

public class Foo {
    public static void main(String[] args) throws Exception {
        for (int i = 0; i < 10; i++)
             run();
    }

    public static void run() {
        final long start = System.nanoTime();

        Random r = new Random();
        double x = 0;
        for(int i=0; i<50000000; i++)
            x += r.nextDouble();

        final long time = TimeUnit.MILLISECONDS.convert(System.nanoTime() - start, TimeUnit.NANOSECONDS);
        System.out.println("time (ms): " + time + " total: " + x);
    }
}

Когато просто стартирам програмата, получавам времена за изпълнение (за run) от около 1s. Въпреки това, когато го стартирам от leiningen така:

lein run -m Foo

Получавам време за работа от около 2s! Как Clojure/Leiningen успява да забави толкова много цяла Java програма? какво правя грешно

Опитах се да прегледам свойствата на системата и в двете изпълнения и не можах да намеря нищо впечатляващо (като различни JIT настройки). И в двата случая използвам Java 7 със сървърния компилатор.

РЕДАКТИРАНЕ: Не знам защо този въпрос е гласуван против. Не съм против Clojure. Напротив, обичам Clojure и ще го използвам. Просто имам този сериозен проблем с производителността, който абсолютно трябва да разреша.

АКТУАЛИЗАЦИЯ: Изпълнението на lein trampoline решава проблема! (макар че нямам представа защо) Актуализирах въпроса, за да отрази, че това наистина е проблем на Leiningen, а не на Clojure.

Друга актуализация: Това се случва и за всеки код на Clojure. Бягането без батут забавя кода с до 5 пъти.


person pron    schedule 18.04.2013    source източник
comment
Съвет: lein help trampoline   -  person noahlz    schedule 28.04.2013


Отговори (3)


Създателите на leiningen са наясно с това и дават подробно обяснение защо това е така и какво можете да направите по въпроса.

https://github.com/technomancy/leiningen/wiki/Faster

Свързан въпрос: Защо leiningen е толкова бавен, когато стартира?

person tixel    schedule 17.03.2015

Вероятно се дължи на различно поведение на JIT.

Производителността на компилирания JIT може да бъде повлияна от редица неща, включително:

  • Какъв код за стартиране се извиква, което ще повлияе на JIT статистиката
  • Какви други класове са били заредени (напр. други подкласове на Random), които биха могли да повлияят на оптимизацията на компилатора за изпращане на извикване на метод
person mikera    schedule 18.04.2013
comment
Опитах и ​​двете с -XX:+PrintCompilation. И в двата случая run() се компилира (единствената интересна функция тук). Вижте обаче актуализацията. По някакъв начин лейнингенът причинява това. - person pron; 18.04.2013

leiningen отнема около секунда, за да започне.

person Joost Diepenmaat    schedule 18.04.2013
comment
Очевидно не броим времето за стартиране на lein. Вижте програмата. Гледам времената в метода на изпълнение. - person pron; 18.04.2013
comment
Прав си. Предполагам, че там се случва нещо странно. Сигурен ли си, че имаш същите неща в пътеката на класа? - person Joost Diepenmaat; 18.04.2013
comment
Също така: може да имате различни ограничения на паметта, така че програмата, стартирана от lein, може да трябва да извършва повече събиране на боклук. Проблемът е труден за диагностициране без точните настройки/свойства на системата. - person Joost Diepenmaat; 18.04.2013
comment
Изобщо не се събира боклук, докато програмата работи (проверено с -verbose:gc). За да бъде събран боклукът, той първо трябва да бъде създаден и не мисля, че Clojure/lein може по някакъв начин да накара алгоритъма да произвежда повече боклук. - person pron; 18.04.2013