2016-05-18 33 views
5

Zamanın neden bir işlevi büyük ölçüde sarmalayarak bunu neden bir işlevle sardığını açıklayabilir mi?Neden bu işlevi bir işlevde çalıştırmak 10x daha uzun sürüyor?

user> (time (loop [n 0 t 0] 
       (if (= n 10000000) 
       t 
       (recur (inc n) (+ t n))))) 
"Elapsed time: 29.312145 msecs" 
49999995000000 

user> (defn tl [r] (loop [n 0 t 0] 
        (if (= n r) 
         t 
         (recur (inc n) (+ t n))))) 
#<[email protected]: #object[user$eval3462$tl__3463 0x7d8ba46 "[email protected]"]> 

user> (time (tl 10000000)) 
"Elapsed time: 507.333844 msecs" 
49999995000000 

Böyle basit bir yinelemenin nasıl daha hızlı yapılabileceğini merak ediyorum. Örneğin, C++'daki benzer yineleme döngüsü, Release modunda 1 ms'den daha az veya bu Clojure koduyla aynı sistemde Debug modunda yaklaşık 20 ms alır.

cevap

9

Bunun nedeni, ikinci durumda aktarılan argümanın kutlandığından olur. Bunu düzeltmek için tip ipucu ekleyin:

user> (defn tl [^long r] 
    (loop [n 0 t 0] 
    (if (= n r) 
     t 
     (recur (inc n) (+ t n))))) 

user> (time (tl 10000000)) 
"Elapsed time: 20.268396 msecs" 
49999995000000 

UPD:

1, 2) bu kadar hızlı neden java ilkel ile çalışır İlk durumda, bu. ^Integer burada çalışmaz, çünkü kutulu tip java.lang.Integer için tür ipucu (bu yüzden büyük harfle yazılmıştır). ^long, java long ilkel için tam olarak ipucudur. Fonksiyon parametreleri için, yalnızca ^long ve ^double ilkel ipuçları (diğerleri desteklenmez. bunlara ek olarak, ^floats, ^bytes vb. Gibi her tür ilkel dizi için tür ipuçları da yapabilirsiniz). 3) Geçilen argüman kutulduktan sonra tüm operasyonlar için jenerik aritmetikleri zorlar. Diğer bir deyişle, her bir + ve inc işlemi yığın üzerinde yeni bir nesne oluşturacaktır (ilkel durumunda, yığınta kalacaktır).

UPD 2:

user> (defn tl [r] 
    (let [r (long r)] 
    (loop [n 0 t 0] 
     (if (= n r) 
     t 
     (recur (inc n) (+ t n)))))) 

user> (time (tl 10000000)) 
"Elapsed time: 18.907161 msecs" 
49999995000000 
+0

iki followups:

alternatif olarak açık bir şekilde döngü önce ilkel geçirilen bağımsız değişkeni dönüştürebilir ima yazmak için hiçbir fark^Integer' 'ile denemiş ; On milyonluk bir arg için neden 'uzun' gereklidir? ve 2) neden 'uzun' küçük harf ama 'Tamsayı' büyük harfle mi yoksa derlenmeyecek mi? 3) arg sadece bir kez geçti, fonksiyon çağrısında, bu "unboxing" bir kez sadece bu kadar büyük bir zaman artışı neden yeterlidir? – johnbakers

+0

@johnbakers Cevabımı uzatacağım – OlegTheCat

İlgili konular