为什么Circe Json与隐式解码器查找相比较,将隐式解码器保存到val.
我期望这些是相同的,因为隐式解析是在运行时完成的.
import io.circe._ import io.circe.generic.auto._ import io.circe.jackson import io.circe.Syntax._ private val decoder = implicitly[Decoder[Data.Type]] def decode(): Either[Error,Type] = { jackson.decode[Data.Type](Data.json)(decoder) } def decodeAuto(): Either[Error,Type] = { jackson.decode[Data.Type](Data.json) } [info] DecodeTest.circeJackson thrpt 200 69157.472 ± 283.285 ops/s [info] DecodeTest.circeJacksonAuto thrpt 200 67946.734 ± 315.876 ops/s
完整的回购可以在这里找到.
https://github.com/stephennancekivell/some-jmh-json-benchmarks-circe-jackson
解决方法
考虑这个更简单的情况,根本不涉及circe或泛型派生:
package demo import org.openjdk.jmh.annotations._ @State(Scope.Thread) @BenchmarkMode(Array(Mode.Throughput)) class OrderingBench { val items: List[(Char,Int)] = List('z','y','x').zipWithIndex val tupleOrdering: Ordering[(Char,Int)] = implicitly @Benchmark def sortWithResolved(): List[(Char,Int)] = items.sorted @Benchmark def sortWithVal(): List[(Char,Int)] = items.sorted(tupleOrdering) }
在我的台式机上的2.11上我得到:
Benchmark Mode Cnt score Error Units OrderingBench.sortWithResolved thrpt 40 15940745.279 ± 102634.860 ps/s OrderingBench.sortWithVal thrpt 40 16420078.932 ± 102901.418 ops/s
如果你看看分配,差异会更大一些:
Benchmark Mode Cnt score Error Units OrderingBench.sortWithResolved:gc.alloc.rate.norm thrpt 20 176.000 ± 0.001 B/op OrderingBench.sortWithVal:gc.alloc.rate.norm thrpt 20 152.000 ± 0.001 B/op
你可以通过打破说明来告诉你发生了什么:
scala> val items: List[(Char,'x').zipWithIndex items: List[(Char,Int)] = List((z,0),(y,1),(x,2)) scala> import scala.reflect.runtime.universe._ import scala.reflect.runtime.universe._ scala> showCode(reify(items.sorted).tree) res0: String = $read.items.sorted(Ordering.Tuple2(Ordering.Char,Ordering.Int))
Ordering.Tuple2这里是一个通用的方法来实例化一个Ordering [(Char,Int)].当我们定义我们的tupleOrdering时,这是完全一样的,但是区别是在val情况下它会发生一次,而在它被隐式解析的情况下,每次调用sort时就会发生这种情况.
因此,您所看到的差异只是在每个操作中实例化解码器实例的成本,而不是在基准代码之外的开始时一次实例化.这个成本相对较小,而对于较大的基准,这将更难看出.