2016-04-07 6 views
3

私はScalaでのタイプキャスティングの使用のコストを分析しようとしています。私が頻繁に使用されるとパフォーマンスが低下する傾向があることに気付きました。のは、例えば、ByteCodec型クラスを見てみましょう:Scalaでのタイプキャストのパフォーマンス

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

だが、その後Longインスタンスを作ってみましょう:

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) 
    } 
} 

私は100百万人を実行すると取得し、プット、これは型クラスのテストのために〜の1200msを取ると〜そうでなければ800ms。オーバーヘッドはどこにありますか?それを取り除くことはできますか?

メインのコード:すでにテストが不正確である理由のコメント一つの理由に言及した

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

JMHを取りますまたはsbt-jmhを使用して分析します。同様の質問のためのガイドがあります:http://shipilev.net/blog/2014/java-scala-divided-we-fail/。上記の純粋なベンチマークは、少なくともval k = ...でのデッドコードの除去とテストを連続して実行するウォームアップの問題に犠牲になります。 –

答えて

7

アレクセイ。

あなたのtypeclassが遅い主な理由は、アプローチ自体とは関係がありません。ボクシング/アンボクシング Longsが遅くなるのです。あなたは@specialized annotationを使用して値クラスのためのあなたの型クラスを特化することができます。

trait ByteCodec[@specialized(Long) T] 

あなたは、ByteBufferから署名を見てみましょ値の型が使用され、何のボクシング/アンボクシングが関与していない場合:

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

もちろん、それは '@ special'でした!私はそれについて考えなかったが、今は明らかだ。私はスケアックが「ロング」を最適化していたのは、あるケースではなく、他のケースでは最適化していなかったということです。今私は同様のパフォーマンスを持っています。 – mariop

+0

コメントは、壊れたuベンチマークがオーバーヘッドを報告するのではなく、オーバーヘッドがないことを意味します。 –

+1

特殊化を使用したベンチマークの違いは何ですか? – pedrofurla

関連する問題