2012-05-24 3 views
10

Vector.min является implemented вКаким образом Scala может избежать штрафа за бокс и распаковку?

def min[B >: A](implicit cmp: Ordering[B]): A = { 
    if (isEmpty) 
    throw new UnsupportedOperationException("empty.min") 
    reduceLeft((x, y) => if (cmp.lteq(x, y)) x else y) 
} 

и когда профиль

Vector.fill(1000000)(scala.util.Random.nextLong).min 

это быстро и нет никакого бокса или распаковка происходит. Однако, если вы пишете по-видимому, эквивалентны

val cmp = implicitly[Ordering[Long]] 
Vector.fill(1000000)(scala.util.Random.nextLong).reduceLeft((x, y) => if (cmp.lteq(x, y)) x else y) 

он работает примерно в 10 раз медленнее (без учета времени в случайном, которые в противном случае доминирует над этим, и да, я нагретым моими тестами до ...).

Как первая версия избегает штрафа за производительность бокса?

Edit: вот мой профилирующий код:

val cmp = implicitly[Ordering[Long]] 

def randomLongs = Vector.fill(1000000)(scala.util.Random.nextLong) 

def timing[R](f: => R): (Long, R) = { 
    val startTime = System.nanoTime 
    val result = f 
    ((System.nanoTime - startTime)/1000000, result) 
} 

def minTiming = { val r = randomLongs; timing(r.min)._1 } 
def reduceLeftTiming = { val r = randomLongs; timing(r.reduceLeft((x, y) => if (cmp.lteq(x, y)) x else y))._1 } 

while(true) { 
    println((minTiming, reduceLeftTiming)) 
} 

и я вижу раз, используя min около 20мс, используя reduceLeft из ~ 200мс. Я профилировал этот код, используя YourKit; вот screen grab дерева вызовов, показывающее, что min не приводит к боксу.

+0

Извините, у меня нет времени проверять себя прямо сейчас, но, видимо, вы используете 'сокращение' в своей собственной реализации вместо' reduceLeft'. Может ли это объяснить замедление? – paradigmatic

+1

«нет бокса или распаковки» - как вы пришли к такому выводу (как я этому не верю) –

+0

@paradigmatic, oops, fixed, не влияет на то, что я вижу. –

ответ

5

Я думаю, что первая версия соответствует java.lang.Long для B. Таким образом, по-прежнему продолжается бокс, но только при заполнении вектора, а затем все сравнения между бокс-объектами.

Во втором варианте, так как тип cmp дается как Ordering[Long], java.lang.Long с в векторе должны быть Unboxed перед передачей cmp.lteq(x, y).