2016-04-07 23 views
3

Scala'daki tipeceleri kullanmanın performans maliyetini analiz etmeye çalışıyorum çünkü yaygın olarak kullanıldığında performansın düşme eğiliminde olduğunu fark ettim. en Örneğin alalım, bir ByteCodec typeclass:Scala'da türünün performansı

trait ByteCodec[T] { 
    def put(index: Int, byteBuffer: ByteBuffer, t: T): Unit 
    def get(index: Int, byteBuffer: ByteBuffer): T 
} 

Let o sırada bir Long örneği olun: Ben 100 milyonlarca alır ve koyar çalıştırırsanız

object ByteCodec { 
    def apply[T](implicit bc: ByteCodec[T]): ByteCodec[T] = bc 

    implicit val longBC = new ByteCodec[Long] { 
    @inline override def put(index: Int, byteBuffer: ByteBuffer, long: Long): Unit = { 
     val _ = byteBuffer.putLong(index, long) 
    } 

    @inline override def get(index: Int, byteBuffer: ByteBuffer): Long = 
     byteBuffer.getLong(index) 
    } 
} 

, bu ~ typeclass testi ve için ~ 1200ms alır Aksi takdirde 800ms. Tepegöz nerede ve ondan kurtulabilir miyim?

ana kod: zaten test hatalı olmasının bir açıklama tek bir nedeni belirtilen

object Main extends App { 
    val cycles = 100000000 
    val byteBuffer = ByteBuffer.allocate(java.lang.Long.BYTES) 
    var start = System.currentTimeMillis() 
    var currCycle = cycles 
    while (currCycle > 0) { 
    byteBuffer.putLong(0, 10L) 
    val k = byteBuffer.getLong(0) 
    currCycle -= 1 
    } 
    var end = System.currentTimeMillis() 
    println(s"time elapsed byteBuffer ${ end - start }") 

    val codec = ByteCodec[Long] 
    start = System.currentTimeMillis() 
    currCycle = cycles 
    while (currCycle > 0) { 
    codec.put(0, byteBuffer, 10L) 
    val k = codec.get(0, byteBuffer) 
    currCycle -= 1 
    } 
    end = System.currentTimeMillis() 
    println(s"time elapsed ByteCodec ${ end - start }") 
} 
+2

alın JMH veya sbt-jmh ve analiz edin. İşte benzer bir soru için bir rehber: http://shipilev.net/blog/2014/java-scala-divided-we-fail/. Yukarıdaki naif kriter, en azından “val k = ...” de ölü kodun ortadan kaldırılmasıyla ve arka arkaya testlerle çalışan ısınma sorunlarıyla karşılaşmaktadır. –

cevap

7

Aleksey.

Bundan başka, yazıcınızın daha yavaş olmasının ana sebebi, yaklaşımın kendisiyle hiçbir ilgisi yoktur: , daha yavaş yapan Longs. Sen kullanarak değer sınıfları için typeclass uzmanlaşabilir @specialized annotation:

trait ByteCodec[@specialized(Long) T] 

Eğer ByteBuffer gelen imzalar bir göz atacak olursak, değer türleri kullanılır ve hiçbir boks/unboxing ilgilenmektedir:

public abstract ByteBuffer putLong(int index, long value); 
public abstract long getLong(int index); 
+1

Tabii ki, 'uzman' oldu! Bunu düşünmedim ama şimdi açık. Sanırım sorun şu ki, scalac bir örnekte "Long" u optimize ediyor, diğerinde değil. Şimdi benzer performansa sahibim. – mariop

+0

Yorum, kırık u-benchmark'ın ek yük olmadığını rapor etmediği anlamına gelir. –

+1

Uzmanlık kullanarak karşılaştırmalar arasındaki fark nedir? – pedrofurla