问题是拳击。创建一个对象比添加两个数字需要更长的时间,但是如果您使用通用(非专业)折叠,则每次都必须创建一个对象。只对所有内容进行专门化的问题在于,您将整个库扩大了 100 倍,因为您需要两个原始参数(包括非原始参数)的每种组合,以及原始的无类型参数版本。(100 倍,因为有 8 个原语加上Unit
/ AnyRef
non-specialized T
。)这是站不住脚的,并且由于没有现成的替代解决方案,因此集合目前是非专业化的。
此外,专业化本身相对较新,因此在实施方面仍有一些缺陷。特别是,您似乎遇到了一个问题SpecializedIterator
: in 中的函数foreach
最终没有专门化(我将 trait/object 东西折叠成一个类,以便更容易追踪):
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