Diğer cevapların hiçbiri, hız farkının birincil nedeninden bahsetmemektedir, bu da zippedsürümün 10.000 tuple tahsisinden kaçınmasıdır. Diğer cevaplar bir çift olarak yapmak notu zipise versiyon, bir ara dizi içerir zippedsürüm değil, ama 10.000 öğeleri için bir dizi tahsis kılan değil zipversiyonunu çok daha kötü-10.000 kısa ömürlü tuples var olduğunu bu diziye konuluyor. Bunlar JVM üzerindeki nesneler tarafından temsil edilir, bu yüzden hemen atacağınız şeyler için bir grup nesne tahsisi yapıyorsunuz.
Bu cevabın geri kalanı bunu nasıl doğrulayabileceğiniz hakkında biraz daha ayrıntıya giriyor.
Daha iyi kıyaslama
JVM'de sorumlu bir şekilde herhangi bir kıyaslama yapmak için jmh gibi bir çerçeve kullanmak istiyorsunuz ve o zaman bile jmh'yi kurmak çok kötü olmasa da sorumlu kısım zor. Eğer böyle bir şey varsa project/plugins.sbt:
addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.3.7")
Ve bunun build.sbtgibi (kullandığınız şeyden bahsettiğinizden 2.11.8 kullanıyorum):
scalaVersion := "2.11.8"
enablePlugins(JmhPlugin)
Ardından kıstasınızı şu şekilde yazabilirsiniz:
package zipped_bench
import org.openjdk.jmh.annotations._
@State(Scope.Benchmark)
@BenchmarkMode(Array(Mode.Throughput))
class ZippedBench {
val arr1 = Array.fill(10000)(math.random)
val arr2 = Array.fill(10000)(math.random)
def ES(arr: Array[Double], arr1: Array[Double]): Array[Double] =
arr.zip(arr1).map(x => x._1 + x._2)
def ES1(arr: Array[Double], arr1: Array[Double]): Array[Double] =
(arr, arr1).zipped.map((x, y) => x + y)
@Benchmark def withZip: Array[Double] = ES(arr1, arr2)
@Benchmark def withZipped: Array[Double] = ES1(arr1, arr2)
}
Ve şununla çalıştır sbt "jmh:run -i 10 -wi 10 -f 2 -t 1 zipped_bench.ZippedBench":
Benchmark Mode Cnt Score Error Units
ZippedBench.withZip thrpt 20 4902.519 ± 41.733 ops/s
ZippedBench.withZipped thrpt 20 8736.251 ± 36.730 ops/s
Bu, zippedsürümün yaklaşık% 80 daha fazla verim aldığını gösterir , bu da muhtemelen ölçümlerinizle aynı veya daha az aynıdır.
Tahsislerin ölçülmesi
Ayrıca jmh'den ayırmaları ölçmesini isteyebilirsiniz -prof gc:
Benchmark Mode Cnt Score Error Units
ZippedBench.withZip thrpt 5 4894.197 ± 119.519 ops/s
ZippedBench.withZip:·gc.alloc.rate thrpt 5 4801.158 ± 117.157 MB/sec
ZippedBench.withZip:·gc.alloc.rate.norm thrpt 5 1080120.009 ± 0.001 B/op
ZippedBench.withZip:·gc.churn.PS_Eden_Space thrpt 5 4808.028 ± 87.804 MB/sec
ZippedBench.withZip:·gc.churn.PS_Eden_Space.norm thrpt 5 1081677.156 ± 12639.416 B/op
ZippedBench.withZip:·gc.churn.PS_Survivor_Space thrpt 5 2.129 ± 0.794 MB/sec
ZippedBench.withZip:·gc.churn.PS_Survivor_Space.norm thrpt 5 479.009 ± 179.575 B/op
ZippedBench.withZip:·gc.count thrpt 5 714.000 counts
ZippedBench.withZip:·gc.time thrpt 5 476.000 ms
ZippedBench.withZipped thrpt 5 11248.964 ± 43.728 ops/s
ZippedBench.withZipped:·gc.alloc.rate thrpt 5 3270.856 ± 12.729 MB/sec
ZippedBench.withZipped:·gc.alloc.rate.norm thrpt 5 320152.004 ± 0.001 B/op
ZippedBench.withZipped:·gc.churn.PS_Eden_Space thrpt 5 3277.158 ± 32.327 MB/sec
ZippedBench.withZipped:·gc.churn.PS_Eden_Space.norm thrpt 5 320769.044 ± 3216.092 B/op
ZippedBench.withZipped:·gc.churn.PS_Survivor_Space thrpt 5 0.360 ± 0.166 MB/sec
ZippedBench.withZipped:·gc.churn.PS_Survivor_Space.norm thrpt 5 35.245 ± 16.365 B/op
ZippedBench.withZipped:·gc.count thrpt 5 863.000 counts
ZippedBench.withZipped:·gc.time thrpt 5 447.000 ms
… gc.alloc.rate.normMuhtemelen en ilginç kısım nerede?zip versiyonun üç katından fazla tahsis edildiğini gösteriyor zipped.
Zorunlu uygulamalar
Bu yöntemin son derece performansa duyarlı bağlamlarda çağrılacağını bilseydim, muhtemelen şu şekilde uygularım:
def ES3(arr: Array[Double], arr1: Array[Double]): Array[Double] = {
val minSize = math.min(arr.length, arr1.length)
val newArr = new Array[Double](minSize)
var i = 0
while (i < minSize) {
newArr(i) = arr(i) + arr1(i)
i += 1
}
newArr
}
Diğer yanıtları birinde optimize sürümü, aksine bu kullandığını unutmayın whileyerine ait forberi forhala Scala koleksiyonları operasyonları içine desugar edecektir. Bu uygulamayı ( withWhile), diğer yanıtın optimize edilmiş (ancak yerinde değil) uygulamasını ( withFor) ve iki orijinal uygulamayı karşılaştırabiliriz:
Benchmark Mode Cnt Score Error Units
ZippedBench.withFor thrpt 20 118426.044 ± 2173.310 ops/s
ZippedBench.withWhile thrpt 20 119834.409 ± 527.589 ops/s
ZippedBench.withZip thrpt 20 4886.624 ± 75.567 ops/s
ZippedBench.withZipped thrpt 20 9961.668 ± 1104.937 ops/s
Bu, zorunlu ve işlevsel sürümler arasında gerçekten büyük bir farktır ve tüm bu yöntem imzaları tamamen aynıdır ve uygulamalar aynı semantiğe sahiptir. Zorunlu uygulamalar küresel devlet vb. Kullanıyor gibi değil.zip Ve zippedsürümleri daha okunaklı , kişisel olarak zorunlu sürümlerin "Scala ruhuna" karşı bir anlamı olduğunu düşünmüyorum ve tereddüt etmem onları kendim kullanmak için.
Tablo ile
Güncelleme: Başka bir tabulateyanıttaki yoruma dayanarak karşılaştırmaya bir uygulama ekledim :
def ES4(arr: Array[Double], arr1: Array[Double]): Array[Double] = {
val minSize = math.min(arr.length, arr1.length)
Array.tabulate(minSize)(i => arr(i) + arr1(i))
}
zipZorunlu olanlardan çok daha yavaş olmasına rağmen , sürümlerden çok daha hızlı :
Benchmark Mode Cnt Score Error Units
ZippedBench.withTabulate thrpt 20 32326.051 ± 535.677 ops/s
ZippedBench.withZip thrpt 20 4902.027 ± 47.931 ops/s
Bir işlevi çağırmanın doğası gereği pahalı bir şey olmadığı ve dizi öğelerine dizinle erişilmesi çok ucuz olduğu için beklediğim şey budur.