Không có câu trả lời nào khác đề cập đến lý do chính cho sự khác biệt về tốc độ, đó là zipped phiên bản tránh được 10.000 phân bổ. Như một vài câu trả lời khác cần lưu ý, zipphiên bản liên quan đến một mảng trung gian, trong khi zippedphiên bản thì không, nhưng việc phân bổ một mảng cho 10.000 phần tử không phải là điều khiến zipphiên bản tệ hơn nhiều, đó là 10.000 bộ dữ liệu ngắn. đang được đưa vào mảng đó. Chúng được đại diện bởi các đối tượng trên JVM, vì vậy bạn đang thực hiện một loạt các phân bổ đối tượng cho những thứ mà bạn sẽ vứt bỏ ngay lập tức.
Phần còn lại của câu trả lời này chỉ đi vào chi tiết hơn một chút về cách bạn có thể xác nhận điều này.
Điểm chuẩn tốt hơn
Bạn thực sự muốn sử dụng một khung công tác như jmh để thực hiện bất kỳ loại điểm chuẩn nào có trách nhiệm trên JVM, và ngay cả phần có trách nhiệm cũng khó, mặc dù việc thiết lập jmh không quá tệ. Nếu bạn có mộtproject/plugins.sbt như thế này:
addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.3.7")
Và một build.sbt như thế này (Tôi đang sử dụng 2.11.8 vì bạn đề cập đến những gì bạn đang sử dụng):
scalaVersion := "2.11.8"
enablePlugins(JmhPlugin)
Sau đó, bạn có thể viết điểm chuẩn của bạn như thế này:
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)
}
Và chạy nó với 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
Điều đó cho thấy rằng zippedphiên bản nhận được thông lượng nhiều hơn khoảng 80%, có thể ít nhiều giống với số đo của bạn.
Đo lường phân bổ
Bạn cũng có thể yêu cầu jmh đo lường phân bổ với -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
Ở đâu gc.alloc.rate.normcó lẽ là phần thú vị nhất, cho thấy zipphiên bản được phân bổ nhiều gấp ba lầnzipped .
Thực hiện bắt buộc
Nếu tôi biết rằng phương pháp này sẽ được gọi trong bối cảnh cực kỳ nhạy cảm với hiệu suất, có lẽ tôi sẽ thực hiện nó như thế này:
  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
  }
Lưu ý rằng không giống như các phiên bản được tối ưu hóa trong một trong những câu trả lời khác, sử dụng này whilethay vì một fortừ forvẫn sẽ desugar vào Scala bộ sưu tập các hoạt động. Chúng ta có thể so sánh việc triển khai này ( withWhile), triển khai ( nhưng không tại chỗ) của câu trả lời khác ( withFor) và hai triển khai ban đầu:
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
Đó thực sự là một sự khác biệt rất lớn giữa các phiên bản mệnh lệnh và chức năng, và tất cả các chữ ký phương thức này hoàn toàn giống hệt nhau và việc triển khai có cùng một ngữ nghĩa. Nó không giống như các triển khai bắt buộc đang sử dụng nhà nước toàn cầu, vv Trong khi zipvàzipped phiên bản phiên bản dễ đọc hơn, cá nhân tôi không nghĩ có bất kỳ ý nghĩa nào trong đó các phiên bản bắt buộc chống lại "tinh thần Scala", và tôi sẽ không ngần ngại để sử dụng chúng cho mình.
Với bảng
Cập nhật: Tôi đã thêm một tabulatetriển khai vào điểm chuẩn dựa trên một nhận xét trong câu trả lời khác:
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))
}
Nó nhanh hơn nhiều so với các zipphiên bản, mặc dù vẫn chậm hơn nhiều so với các phiên bản bắt buộc:
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
Đây là những gì tôi mong đợi, vì vốn dĩ không có gì đắt khi gọi hàm và bởi vì việc truy cập các phần tử mảng theo chỉ mục là rất rẻ.