2

プリミティブの大きな配列を折りたたむいくつかの方法 (「直接」および反復子を使用) をベンチマークしましたが、結果は期待外れです。(はい、ウォームアップ、中間 GC、および多くの実行パスを実行し、JVM をサーバー モードで実行し、scalac最適化を有効にしました (デバッグ情報は無効にしました))。

ここに投稿するにはコードが大きすぎると思うので、リンクは次のとおり です。

@inline def array_foldl[@specialized A, @specialized B](init: B)(src: Array[A])(fun: (B, A) => B) = {
  var res = init
  var i = 0
  var len = src.length
  while (i < len) {
    res = fun(res, src(i))
    i += 1
  }
  res
}

他の視覚的に優れた方法は、完全に部外者です。また、イテレータの抽象化を使用すると、すべての場合で失敗します。手書きのパロディを標準的なイテレータと呼ぶSpecializedIteratorとわずかに速くなります。だから問題は何ですか?どうにか改善できないでしょうか?「速い」イテレータを作成する方法はありますか、それとも原理自体に大きな問題がありますか?
ご清聴ありがとうございました。

4

1 に答える 1

4

問題はボクシング。2 つの数値を加算するよりもオブジェクトを作成する方がはるかに時間がかかりますが、一般的な (特殊化されていない) 折り畳みを使用する場合は、毎回オブジェクトを作成する必要があります。すべてを特殊化するだけの問題は、2 つのプリミティブ パラメーター (非プリミティブを含む) のすべての組み合わせと、元の型パラメーターのないバージョンが必要になるため、ライブラリ全体が 100 倍大きくなることです。(100x は、8 つのプリミティブと /non-specialized があるためUnitですAnyRefT) これは支持できず、すぐに利用できる代替ソリューションがないため、コレクションは現在、特化されていません。

また、専門化自体は比較的新しいため、その実装にはまだいくつかの欠陥があります。特に、あなたは 1 つをヒットしたようですSpecializedIterator: 関数のforeach特殊化は終了しません (追跡しやすくするために、特性/オブジェクトのことを単一のクラスにまとめました):

public class Main$SpecializedArrayIterator$mcJ$sp extends Main$SpecializedArrayIterator{
public final void foreach$mcJ$sp(scala.Function1);
  Code:
   0:   aload_0
   1:   invokevirtual   #39; //Method Main$SpecializedArrayIterator.hasNext:()Z
   4:   ifeq    24
   7:   aload_1
   8:   aload_0
   9:   invokevirtual   #14; //Method next$mcJ$sp:()J
   12:  invokestatic    #45; //Method scala/runtime/BoxesRunTime.boxToLong:(J)Ljava/lang/Long;
   15:  invokeinterface #51,  2; //InterfaceMethod scala/Function1.apply:(Ljava/lang/Object;)Ljava/lang/Object;
   20:  pop
   21:  goto    0
   24:  return

12 行目のボックスを参照してください。その後に、特殊化されていない Function1? への呼び出しが続きます。おっとっと。(A, (A,A) => A)(で使用されるタプルsumも特殊化を台無しにします。) このような実装はフルスピードです:

class SpecializedArrayIterator[@specialized A](src: Array[A]) {
  var i = 0
  val l = src.length
  @inline final def hasNext: Boolean = i < l
  @inline final def next(): A = { val res = src(i); i += 1; res }
  @inline final def foldLeft[@specialized B](z: B)(op: (B, A) => B): B = {
    var result = z
    while (hasNext) result = op(result,next)
    result
  }
}

...
measure((new SpecializedArrayIterator[Long](test)).foldLeft(0L)(_ + _))
...

次のような結果が得られます。

Launched 51298 times in 2000 milliseconds, ratio = 25.649    // New impl
Launched 51614 times in 2000 milliseconds, ratio = 25.807    // While loop
于 2013-02-11T23:34:06.213 に答える