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