Дорогая производительность CollectionConverters, несмотря на то, что она является оберткой? - PullRequest
4 голосов
/ 05 февраля 2020

AFAIU, CollectionConverters - это оболочки, просто делегирующие вызовы в базовую коллекцию, поэтому стоимость должна состоять в выделении одного объекта, а затем в косвенном вызове метода, например, Преобразование между Java и Scala Collections состояний

Внутренне, эти преобразования работают, устанавливая объект-оболочку, который перенаправляет все операции в базовый объект коллекции. Таким образом, коллекции никогда не копируются при преобразовании между Java и Scala.

Анализ SetWrapper на самом деле мы видим, что он просто делегирует вызов underlying collection

class SetWrapper[A](underlying: Set[A]) extends ju.AbstractSet[A] with Serializable { self =>
  ...
  def size = underlying.size
  ...
}

Однако рассмотрим следующий эталонный тест jmh

import org.openjdk.jmh.annotations._
import scala.jdk.CollectionConverters._
import java.{util => ju}

@State(Scope.Benchmark)
@BenchmarkMode(Array(Mode.Throughput))
class So31830028 {
  val size = 1000000
  val scalaSet: Set[Int] = (1 to size).toSet
  val javaSet: ju.Set[Int]  = (1 to size).toSet.asJava

  @Benchmark def scala = scalaSet.size
  @Benchmark def scalaAsJava = scalaSet.asJava.size
  @Benchmark def java = javaSet.size
  @Benchmark def javaAsScala = javaSet.asScala.size
}

, где sbt "jmh:run -i 10 -wi 5 -f 2 -t 1 bench.So31830028" дает

[info] Benchmark                     Mode  Cnt          Score          Error   Units
[info] So31830028.java              thrpt   20  356515729.840 ± 64691657.672   ops/s
[info] So31830028.javaAsScala       thrpt   20  270053471.338 ± 36854051.611   ops/s
[info] So31830028.scala             thrpt   20  448415156.726 ± 53674976.259   ops/s
[info] So31830028.scalaAsJava       thrpt   20  211808793.234 ± 57898858.737   ops/s

Почему, кажется, существует значительное снижение производительности, если CollectionConverters простые обертки?

Вопрос вызван Стоимость неявного преобразования из java в scala коллекций

1 Ответ

2 голосов
/ 05 февраля 2020

В 2.12 scalaSet.size - это просто поле доступа ; для 2.13 это тривиальный вызов метода доступа к полю в конечном классе , который должен быть очень простым для вставки, поэтому

выделение одного объекта, а затем косвенное обращение к одному методу

может быть нетривиальными издержками по сравнению с этим .

Я не понимаю, в чем разница между java и javaAsScala (правка: duh это еще одно косвенное указание).

...