Почему программа Clojure Hello World такая медленная по сравнению с Java и Python? - PullRequest
11 голосов
/ 28 марта 2010

Обновление

Как полагают многие, похоже, что это произошло из-за того, что код clojure был сначала скомпилирован, а затем выполнен.Компиляция AOT должна помочь компенсировать это.Учитывая, что практический процесс компиляции Clojure AOT оказался немного сложным (проблемы с classpath, проблемы с каталогами и т. Д.), Я написал небольшой пошаговый процесс здесь на случай, если кому-то будет интересно.


Привет всем,

Я читаю "Программирование Clojure", и я сравнивал некоторые языки, которые я использую для некоторого простого кода.Я заметил, что реализации clojure были самыми медленными в каждом случае.Например,

Python - hello.py

def hello_world(name):
  print "Hello, %s" % name

hello_world("world")

и результат,

$ time python hello.py
Hello, world

real    0m0.027s
user    0m0.013s
sys 0m0.014s

Java - hello.java

import java.io.*;

public class hello {
  public static void hello_world(String name) {
    System.out.println("Hello, " + name);
  }

  public static void main(String[] args) {
    hello_world("world");
  }
}

и результат,

$ time java hello
Hello, world

real    0m0.324s
user    0m0.296s
sys 0m0.065s

и, наконец,

Clojure - hellofun.clj

(defn hello-world [username]
  (println (format "Hello, %s" username)))

(hello-world "world")

и результаты,

$ time clj hellofun.clj 
Hello, world

real    0m1.418s
user    0m1.649s
sys 0m0.154s

Вот и все, гарангутан 1,4 секунды!

У кого-нибудь есть указатели на то, что может быть причиной этого?Действительно ли Clojure такой медленный, или есть уловки JVM и др., Которые необходимо использовать для ускорения выполнения?

Что еще более важно - не станет ли эта огромная разница в производительности проблемой в какой-то момент??(Я имею в виду, скажем, я использовал Clojure для производственной системы - выигрыш от использования lisp, похоже, полностью компенсируется проблемами с производительностью, которые я вижу здесь).


Используемая здесь машина - Macbook Pro 2007 года, работающий под управлением Snow Leopard, 2,16 ГГц Intel C2D и 2G DDR2 SDRAM.

Кстати, используемый мной сценарий clj здесь и выглядит как

#!/bin/bash
JAVA=/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home/bin/java
CLJ_DIR=/opt/jars
CLOJURE=$CLJ_DIR/clojure.jar
CONTRIB=$CLJ_DIR/clojure-contrib.jar
JLINE=$CLJ_DIR/jline-0.9.94.jar
CP=$PWD:$CLOJURE:$JLINE:$CONTRIB

# Add extra jars as specified by `.clojure` file
if [ -f .clojure ]
then
  CP=$CP:`cat .clojure`
fi

if [ -z "$1" ]; then
  $JAVA -server -cp $CP \
      jline.ConsoleRunner clojure.lang.Repl
else
  scriptname=$1
  $JAVA -server -cp $CP clojure.main $scriptname -- $*
fi

Ответы [ 4 ]

27 голосов
/ 28 марта 2010

Вы не измеряете здесь много, кроме времени загрузки Clojure. Вы также запускаете свою программу таким образом, что вы также измеряете время компиляции. Если вы хотите увидеть более быстрое время загрузки, вам нужно заранее скомпилировать код.

Немного кодировав в Python, я обнаружил, что Clojure, как правило, намного, намного, намного быстрее, чем Python, и вы обычно можете заставить программу Clojure достигать 2X-4X скорости чистой Java.

2 голосов
/ 29 марта 2010

Также обратите внимание, что опция '-server' в вашем сценарии clj будет использовать 'серверную JVM', которая оптимизирована для длительных процессов за счет более медленного времени запуска.

Ваш пример Java не включал эту опцию, поэтому он, вероятно, использует «клиентскую JVM», которая оптимизирована для более быстрого запуска.

Попробуйте выполнить java -jar clojure.jar -i hellofun.clj для более справедливого сравнения.

2 голосов
/ 28 марта 2010

Чтобы добавить к ответу dnolen, при выполнении содержимого синхронизации Python vs Clojure, вы можете упаковать «базовую единицу работы» как функцию, а затем использовать макрос time (в Clojure) или функцию timeit.timeit (в Python; или, еще лучше, использовать средства синхронизации IPython) в REPL. Результаты должны быть примерно сопоставимы. (Обратите внимание, что код Clojure необходимо «прогреть», запустив его несколько раз для достижения полной производительности.)

Есть также несколько тестов для Clojure, например Criterium ; Вы можете рассмотреть возможность использования одного из них.

1 голос
/ 21 ноября 2016

JVM в целом уже имеет несколько медленное время запуска по сравнению с родными или интерпретируемыми языками. Кроме того, Clojure значительно увеличивает время запуска, так как при запуске компилирует и загружает довольно много кода. Даже с AOT есть много вещей, которые Clojure необходимо настроить, прежде чем он сможет работать.

Итог, не зависящий от Clojure для короткоживущих процессов. В большинстве случаев даже не полагайтесь на Java в этих случаях. Что-то родное или интерпретируемое, как Node.js, Python, Lua и т. Д., Было бы намного лучше.

Однако для средне- и долгоживущих процессов Clojure будет в среднем намного быстрее, чем почти все другие динамические языки, превосходя Python и Ruby. При необходимости Clojure можно сделать почти так же быстро, как и Java, без особых усилий, и его взаимодействие с Java настолько просто, что, изменив несколько функций на чисто Java, вы в большинстве случаев сможете получить скорость, равную Java.

Теперь, если вы действительно хотите что-то быстрое для Clojure, я бы рекомендовал изучить lumo . Это REPL ClojureScript, который самодостаточен и работает на загрузочном ClojureScript, так что никакой JVM не видно.

time python -c "print(\"Hello World\")"
Hello World

real    0m0.266s
user    0m0.015s
sys     0m0.202s

time lumo -e "\"Hello World\""
"Hello World"

real    0m0.438s
user    0m0.000s
sys     0m0.203s

Как вы можете видеть, Lumo приближается к скорости запуска Cpy3k.

Альтернатива, которая больше не будет Clojure, но все равно будет вдохновленным Clojure Лиспом, - Hy . Это Лисп с синтаксисом Clojure, работающим на Python.

time hy -c "(print \"Hello World\")"
Hello World

real    0m0.902s
user    0m0.000s
sys     0m0.171s

Время его запуска немного медленнее, чем у Cpy3k и Lumo, но он предоставляет вам весь Python с вашим синтаксисом и макросами Clojure.

...