是否将scala缓存转换为功能接口

问题描述 投票:4回答:3

Scala 2.12可以自动将lambda表达式转换为接口。例如,我正在使用:

import org.apache.kafka.common.serialization.{Deserializer, Serde, Serializer}
import scalapb.GeneratedMessageCompanion

class ProtoSerde[A <: scalapb.GeneratedMessage](implicit companion: GeneratedMessageCompanion[A])
  extends Serde[A] {
  override def serializer(): Serializer[A] = (_: String, data: A) => data.toByteArray

  override def deserializer(): Deserializer[A] = (_: String, data: Array[Byte]) => companion.parseFrom(data)
}

它会自动缓存创建的对象的实例,这样就不会在每个调用中分配一个新对象。即我想要:

import org.apache.kafka.common.serialization.{Deserializer, Serde, Serializer}
import scalapb.GeneratedMessageCompanion

class ProtoSerde[A <: scalapb.GeneratedMessage](implicit companion: GeneratedMessageCompanion[A])
  extends Serde[A] {
  lazy val _serializer: Serializer[A] = (_: String, data: A) => data.toByteArray
  lazy val _deserializer: Deserializer[A] = (_: String, data: Array[Byte]) => companion.parseFrom(data)

  override def serializer(): Serializer[A] = _serializer

  override def deserializer(): Deserializer[A] = _deserializer
}

编译器将自动执行此优化,还是我必须自己执行此优化?

scala lambda functional-interface single-abstract-method
3个回答
1
投票

def不会记住每次调用都会重新计算值。稍后可能会通过JIT编译器对其进行优化。

但是有一个更简单的解决方案可以使类的属性成为备忘录。当您覆盖父方法时,Scala允许将def更改为val。也可以在扩展类上添加lazy修饰符:

class ProtoSerde[A <: scalapb.GeneratedMessage](implicit companion: GeneratedMessageCompanion[A])
  extends Serde[A] {
  override lazy val serializer: Serializer[A] = (_: String, data: A) => data.toByteArray

  override lazy val deserializer: Deserializer[A] = (_: String, data: Array[Byte]) => companion.parseFrom(data)
}

0
投票

编译器不会执行此类优化。将lambda表达式转换为接口并不意味着将该接口的实例保存为单例或任何其他保存方式。每次调用此Lambda时,它将创建此实例。您需要自己进行此优化。


0
投票

也许最好在您的特定情况下进行基准测试。例如,以下简化代码段的jmh基准]

trait Quxable[A] {
  def qux(x: A): A
}

class FooImpl1 {
  def zar(): Quxable[Int] = (x: Int) => x + 1
}

class FooImpl2 {
  val _zar: Quxable[Int] = (x: Int) => x + 1
  def zar(): Quxable[Int] = _zar
}

// sbt "jmh:run -i 5 -wi 5 -f 2 -t 1 -prof gc bench.So61983239"

@State(Scope.Benchmark)
@BenchmarkMode(Array(Mode.Throughput))
class So61983239 {
  val end = 1000000
  val fooImpl1 = new FooImpl1
  val fooImpl2 = new FooImpl2

  @Benchmark def impl1 = (1 to end) map (x => fooImpl1.zar().qux(x))
  @Benchmark def impl2 = (1 to end) map (x => fooImpl2.zar().qux(x))
}

两者都具有相似的分配率(gc.alloc.rate]

[info] Benchmark                                           Mode  Cnt         Score         Error   Units
[info] So61983239.impl1                                   thrpt   10        76.866 ±       2.690   ops/s
[info] So61983239.impl1:·gc.alloc.rate                    thrpt   10      4790.899 ±     167.414  MB/sec
[info] So61983239.impl1:·gc.alloc.rate.norm               thrpt   10  68637392.621 ±       0.152    B/op
[info] So61983239.impl1:·gc.churn.PS_Eden_Space           thrpt   10      4793.715 ±     174.955  MB/sec
[info] So61983239.impl1:·gc.churn.PS_Eden_Space.norm      thrpt   10  68686591.527 ± 1866568.380    B/op
[info] So61983239.impl1:·gc.churn.PS_Survivor_Space       thrpt   10         6.216 ±       1.411  MB/sec
[info] So61983239.impl1:·gc.churn.PS_Survivor_Space.norm  thrpt   10     89091.175 ±   20368.810    B/op
[info] So61983239.impl1:·gc.count                         thrpt   10       234.000                counts
[info] So61983239.impl1:·gc.time                          thrpt   10      1055.000                    ms
[info] So61983239.impl2                                   thrpt   10        78.027 ±       0.889   ops/s
[info] So61983239.impl2:·gc.alloc.rate                    thrpt   10      4862.226 ±      54.507  MB/sec
[info] So61983239.impl2:·gc.alloc.rate.norm               thrpt   10  68637392.613 ±       0.162    B/op
[info] So61983239.impl2:·gc.churn.PS_Eden_Space           thrpt   10      4895.604 ±     148.716  MB/sec
[info] So61983239.impl2:·gc.churn.PS_Eden_Space.norm      thrpt   10  69105653.917 ± 1668136.154    B/op
[info] So61983239.impl2:·gc.churn.PS_Survivor_Space       thrpt   10         5.582 ±       2.634  MB/sec
[info] So61983239.impl2:·gc.churn.PS_Survivor_Space.norm  thrpt   10     78851.978 ±   37413.327    B/op
[info] So61983239.impl2:·gc.count                         thrpt   10       230.000                counts
[info] So61983239.impl2:·gc.time                          thrpt   10      1073.000                    ms
© www.soinside.com 2019 - 2024. All rights reserved.