2016-06-18 24 views
6

BenScala desen eşleştirme performans

val chars: Array[Char] = some array 

def fun1(idx:Int):Int = { 
    some code here (including the stop condition) 

    val c = chars(idx) 
    c match{ 
     case '(' => fun1(idx+1) 
     case _ => fun1(idx+1) 
    } 

} 

Bu kod 4'tür (bu sadece dizi geçişi var bu sürümü basitleştirilmiş ve herhangi ödev ayrıntılarını içermez) Bu sorunla karşılaştı Ben eşleşen deseni değişiyor yapıyorum Tüm zamanlar

def fun2(idx: Int):Int = { 
    some code here (including the stop condition) 

    val c = chars(idx) 
    (c == '(') match{ 
     case true => fun2(idx+1) 
     case _ => fun2(idx+1) 
    } 
} 

daha yavaş

(ı ScalMeter kullanarak çalıştırıyorum yüzden istatistiklerde inanıyorum).

Bu davranışı herkes açıklayabilir mi?

cevap

2

Sadece ilk match'un yaklaşık% 50 daha yavaş olduğunu doğrulayabilirim, 4x değil (2.11.8). Her neyse, bayt kodu bakarsanız, ilk match öğesinin, switch yönergesiyle birlikte kullanılan ve yönergesine çevrildiğini öğrenebilirsiniz; bu yöntemde, birden çok seçenek içeren bir deyimdir ve temelde bir arama motoru olurken, ikincisi if'a çevrilir. Yani ikinci match basitçe:

if (c == '(') fun2(idx+1) else fun2(idx+1) 
0

Güncelleme aşağıda yanlıştır (bu testlerin zaman çoğunluk verileri oluşturmaya harcanan bu yüzden gerçek kastetmek zamanlarda fark farkedilir değildi bu aynı kriter Koşu. sabit giriş ile, case ')' ve diğer durum için ~ 35 ms için 100 milyon giriş başına 125 ms gösterir.)

Tanımladığınız farkı göremiyorum. ,

def func(s: Seq[Char], idx: Int): String = 
    if(idx == s.length) "foo" else s(idx) match { 
    case ')' => func(s, idx+1) 
    case _ => func(s, idx+1) 
    } 

def func1(s: Seq[Char], idx: Int): String = 
    if(idx == s.length) "foo" else (s(idx) == '(') match { 
    case true => func(s, idx+1) 
    case _ => func(s, idx+1) 
    } 

import scala.util.Random 
def randy = Stream.continually(Random.nextPrintableChar) 


def doit(n: Int)(f: (Seq[Char], Int) => String) = { 
val start = System.currentTimeMillis;  
f(randy.take(n).toIndexedSeq, 0); 
System.currentTimeMillis - start 
} 


scala> doit(1000000)(func) 
res9: Long = 231 

scala> doit(1000000)(func1) 
res10: Long = 238 

scala> doit(1000000)(func) 
res11: Long = 234 

scala> doit(1000000)(func1) 
res12: Long = 201 

Vb Gördüğünüz gibi: ScalaMeter ("kuru" bir kaç kez çalıştırarak "ısınmak" icar sonra) yapar, ancak repl içinde çalıştırmaya nasıl emin değil, ben hemen hemen aynı performansı elde büyük bir fark yok.

+0

Bunun geçerli kıyaslama yöntemine yakın bir şey olduğundan şüphe duyarım. ScalaMeter, sonuçlar kararlı hale gelene kadar onlarca ısınmayı sever. Aynı verileri kullanarak test bile etmiyorsunuz. –

+0

Evet, aynı veriler değil. Ama koşular arasında oldukça yakın sonuçlar alıyorum. Stddev son derece düşüktür, bu da aynı veriyi kullanırsam çok fazla bir fark görmeyeceğimi gösterir. Yanıtta da belirtildiği gibi, ben de ısınma çalışmaları yaptım, bu yüzden "geçersiz" bulduğunuz bu kıyaslamadan emin değilsiniz. Bulgularımın yanında duruyorum ve yapabiliyorsanız, onları kesin olarak (ve tekrarlanabilir şekilde) onaylamamaya itiraz ediyorum. – Dima

+0

İşlevlerinizi ödünç almak için, burada scala metrelik bir ölçüt var: https://gist.github.com/lukaszwawrzyk/a2505d5b3083bb72de51b8445fbb9a76 "char time: 13.172258374999998 ms' ve" bool time: 4.739404575 ms'. Endeksli bir sekme sonuçları gerçekten daha yakın fakat eşit değil (95 saniye vs 80 saniye) –