2010-03-28 28 views
11

Cập nhậtTại sao chương trình Hello World của Clojure quá chậm so với Java và Python?

Theo đề xuất của nhiều người, có vẻ như điều này là do mã clojure được biên dịch lần đầu và sau đó được thực thi. Biên dịch AOT sẽ giúp bù đắp điều đó. Do tôi đã tìm thấy quy trình biên dịch Clojure AOT thực tế một chút khó giải quyết (các vấn đề về classpath, các vấn đề về thư mục và cộng sự), tôi đã viết một bước nhỏ theo từng bước here, trong trường hợp ai đó quan tâm.


Hi all,

tôi đang đọc "Lập trình Clojure" và tôi đã so sánh một số ngôn ngữ tôi sử dụng cho một số mã đơn giản. Tôi nhận thấy rằng việc triển khai clojure là chậm nhất trong mỗi trường hợp. Ví dụ,

Python - hello.py

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

hello_world("world") 

và kết quả,

$ 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"); 
    } 
} 

và kết quả,

$ time java hello 
Hello, world 

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

và cuối cùng,

Clojure - hellofun.clj

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

(hello-world "world") 

và kết quả,

$ time clj hellofun.clj 
Hello, world 

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

Thats một toàn thể, garangutan 1,4 giây!

Có ai có gợi ý về nguyên nhân của việc này có thể là gì không? Clojure có thực sự chậm, hay có thủ thuật JVM và những thứ khác cần phải được sử dụng để tăng tốc độ thực thi?

Quan trọng hơn - không phải sự khác biệt lớn về hiệu suất sẽ là một vấn đề tại một thời điểm nào đó? (Tôi có nghĩa là, cho phép nói rằng tôi đã sử dụng Clojure cho một hệ thống sản xuất - đạt được tôi nhận được trong sử dụng lisp dường như hoàn toàn bù đắp bởi các vấn đề hiệu suất tôi có thể thấy ở đây).


Máy được sử dụng ở đây là Macbook Pro 2007 chạy Snow Leopard, 2.16Ghz Intel C2D và 2G DDR2 SDRAM.

BTW, kịch bản CLJ Tôi đang sử dụng là từ here và trông giống như,

#!/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 
+2

Mỗi lần bạn chạy ví dụ Clojure nó được biên dịch. Nếu bạn muốn đo hiệu suất chạy thì AOT sẽ biên dịch nó. – fogus

+1

Có một lý do rất tốt mà không phải ai cũng đủ can đảm để chuẩn mã. Nó không phải là dễ dàng. Bạn không thể chỉ cần nhấn RUN và xem đồng hồ bấm giờ. – Rayne

+1

@fogus - cảm ơn, tôi đang tìm kiếm trình biên dịch AOT. @Rayne - Tôi không "chấm điểm" mã theo bất kỳ nghĩa đen nào. Tôi muốn giải thích lý do tại sao nó chạy chậm so với các ngôn ngữ khác, và biên dịch theo yêu cầu so với lời giải thích của AOT đã giúp tôi hiểu điều đó! – viksit

Trả lời

27

Bạn không đo nhiều ở đây, ngoại trừ cho thời gian khởi động Clojure. Bạn cũng đang chạy chương trình của mình theo cách mà bạn đang đo thời gian biên dịch. Nếu bạn muốn xem thời gian tải nhanh hơn, bạn cần phải biên dịch trước mã của mình.

Được mã hóa một chút bằng Python, tôi thấy Clojure là một quy tắc chung, nhanh hơn nhiều so với Python và bạn thường có thể có chương trình Clojure để đạt được tốc độ 2X-4X của Java thuần túy .

+0

Bạn nghĩ gì về clojure so với PyPy? Tôi gần đây đã ngạc nhiên rằng một số tính toán lý thuyết đồ thị tôi đã làm nhanh hơn đáng kể trong PyPy hơn trong clojure (và clojure nhanh hơn đáng kể so với CPython). Mã trong cả hai trường hợp chủ yếu là chức năng, sử dụng mảng (danh sách trong Python, vectơ trong clojure), bộ và chuỗi lười (máy phát trong Python). –

+2

Nếu bạn so sánh danh sách có thể thay đổi với vectơ, bạn sẽ thấy sự khác biệt hoàn hảo. Trong Clojure khi perf thực sự quan trọng tôi sẽ sử dụng các mảng Java, hoặc một sự trừu tượng hóa ánh sáng trên chúng. Điều đó nói rằng, perf của PyPy có vẻ thực sự tốt. Tuy nhiên, bây giờ tôi đã quen thuộc/thoải mái với việc hoàn thiện Clojure, tôi nghĩ có một số cách để đi trước khi PyPy cạnh tranh với JVM. – dnolen

2

Để thêm vào dnolen của câu trả lời, khi thực hiện Python vs nội dung thời gian Clojure, bạn có thể muốn gói "đơn vị cơ bản của tác phẩm" của bạn như là một chức năng và sau đó sử dụng time vĩ mô (trong Clojure) hoặc timeit.timeit chức năng (bằng Python hoặc, tốt hơn, sử dụng các cơ sở thời gian của IPython) tại REPL. Các kết quả nên gần như tương đương. (Lưu ý rằng mã Clojure cần phải được "khởi động" bằng cách chạy nó một vài lần để đạt được hiệu suất đầy đủ.)

Ngoài ra còn có một số bộ tiêu chuẩn cho Clojure, ví dụ Criterium; bạn có thể muốn xem xét sử dụng một trong số họ.

+0

Cảm ơn thông tin. Tôi đã sử dụng python timeit cho py benchmarking và perf analysis. Câu hỏi này đã được nhiều hơn trên các dòng - có lẽ có một vấn đề với các thiết lập JVM vv đã gây ra nó. Thực tế là nó được AOT biên dịch giải thích nó đến một mức độ lớn. – viksit

+0

@viksit: Yup, JVM khởi động là yếu tố lớn khác. (Rõ ràng nó không còn là một yếu tố lớn nếu quá trình của bạn có một số lượng đáng kể công việc để làm, nhưng đó không phải là trường hợp với ví dụ "Hello World" - hoặc với một lần chạy qua phần lớn các dấu ấn vi mô mà tôi ' đã nhìn thấy.) –

+0

@downvoter: Trong sự tò mò, phần nào của câu trả lời này bạn không đồng ý? (Nếu nó giống như "thời gian của Clojure không giống như thời gian của Python", thì hãy lưu ý phần "so sánh gần" của câu trả lời (cộng với nhận xét về sự hâm nóng) và tự hỏi liệu điều này có thực sự đủ cho chúng ta không trong cùng một loại ballpark so sánh ... Nếu nó là cái gì khác, tôi thành thật muốn biết.) –

2

Ngoài ra, lưu ý rằng tùy chọn '-server' trong tập lệnh clj của bạn sẽ sử dụng 'JVM máy chủ' được tối ưu hóa cho các quy trình chạy dài với chi phí khởi động chậm hơn.

Ví dụ java của bạn không bao gồm tùy chọn này, vì vậy, có thể sử dụng 'JVM khách hàng', được tối ưu hóa cho thời gian khởi động nhanh hơn.

Thử chạy java -jar clojure.jar -i hellofun.clj để so sánh công bằng hơn.

1

JVM nói chung đã có thời gian khởi động hơi chậm so với ngôn ngữ gốc hoặc phiên dịch. Trên hết, Clojure bổ sung thêm một số tiền đáng kể cho thời gian khởi động, khi nó biên dịch và tải khá nhiều mã khi khởi động. Ngay cả với AOT, có rất nhiều thứ mà Clojure cần thiết lập trước khi nó có thể chạy.

Tóm lại, không phụ thuộc vào Clojure cho các quy trình sống ngắn. Thậm chí không dựa vào Java cho những trường hợp sử dụng hầu hết thời gian. Một cái gì đó bản địa hoặc giải thích như Node.js, Python, Lua, vv sẽ tốt hơn nhiều.

Đối với các quy trình trung bình đến lâu, mặc dù Clojure trung bình sẽ nhanh hơn nhiều so với hầu hết các ngôn ngữ động khác, đánh bại Python và Ruby. Clojure có thể được thực hiện nhanh như Java nếu cần mà không cần nhiều nỗ lực, và Java inter-op của nó rất dễ dàng, bằng cách thay đổi một vài hàm thành java thuần túy, bạn có thể trong hầu hết các trường hợp có tốc độ bằng Java.

Bây giờ, nếu bạn thực sự muốn điều gì đó nhanh chóng cho Clojure, tôi khuyên bạn nên xem xét lumo. ClojureScript REPL của nó tự chứa và chạy trên ClojureScript được khởi động, vì vậy không có JVM nào được nhìn thấy.

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 

Như bạn có thể thấy, Lumo khá gần với tốc độ khởi động của Cpy3k.

Một giải pháp thay thế, không thực sự là Clojure nữa, nhưng nó vẫn sẽ là một cảm hứng của Clojure, là Hy. Cú pháp Lisp với Clojure của nó chạy trên Python.

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

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

Thời gian khởi động của nó hơi chậm hơn cả Cpy3k và Lumo, nhưng nó cung cấp cho bạn tất cả Python theo ý của bạn với cú pháp và macro của Clojure.

+0

Cảm ơn vì điều đó! Tôi đã theo dõi Lumo một thời gian, cũng như đưa ra một sự cân nhắc nghiêm túc cho một dự án. Bạn đã sử dụng hy cho bất kỳ cấp độ sản xuất? Chỉnh sửa: Ngoài ra, một câu trả lời mới sau 6 năm. Chết tiệt, thời gian bay. – viksit

+0

@viksit Tôi đã không thực sự sử dụng Hy trong sản, chỉ đùa với nó vào thời gian của riêng tôi. –

Các vấn đề liên quan