2016-06-22 11 views
24

Đây là mã chuẩn của tôi:Tại sao là Array.slice như vậy (shockingly!) Chậm?

def bm(duration: Long)(f: => Unit)={ 
    val end = System.currentTimeMillis + duration 
    var count = 0 
    while(System.currentTimeMillis < end) { f; count += 1 } 
    count 
} 

val array = new scala.util.Random().alphanumeric.take(1000).toArray 

(1 to 20).map { _ => bm(1000) { array.slice(100,200) } }.sum/20 

Chạy này nhiều lần, tôi luôn có được con số trong sân chơi bóng chày của khoảng 1,5 triệu lát mỗi giây. Từ 1,4 đến 1,6.

Bây giờ, tôi làm điều này:

implicit class FastSlicing(val a: Array[Char]) extends AnyVal { 
    def fastSlice(from: Int, until: Int) = Arrays.copyOfRange(a, from, until) 
} 
(1 to 20).map { _ => bm(1000) { array.fastSlice(100,200) } }.sum/20 

Và kết quả tôi nhận được là từ 16 đến 18 triệu lát mỗi giây. Đây là nhiều hơn 10 lần nhanh hơn.

Bây giờ, tôi biết tất cả các lý do thông thường về các giao dịch mà scala tạo ra để cung cấp các thành ngữ chức năng và an toàn loại đôi khi với chi phí ... Nhưng trong trường hợp này, tôi nghĩ rằng tất cả đều không trả lời câu hỏi đơn giản: tại sao là ArrayOps.slice không được triển khai theo cách này ??? Tôi nhận ra, sẽ có nhiều triển khai giống nhau cần thiết, vì cách thức giao dịch của java với các mảng nguyên thủy, nhưng đó là ít phiền toái nhất, không thực sự là một vấn đề đối phó để đạt được hiệu suất gấp 10 lần.

.slice chỉ là một ví dụ, hầu hết các ops mảng khác dường như cũng gặp phải vấn đề tương tự. Tại sao nó phải theo cách này?

Cập nhật bây giờ, đây là một cái gì đó mà tôi tìm thấy thậm chí gây sốc hơn:

val seq = new scala.util.Random().alphanumeric.take(1000).toIndexedSeq 
(1 to 20).map { _ => bm(1000) { seq.slice(100,200) } }.sum/20 

này làm khoảng 5-6 triệu lát mỗi giây đối với tôi. Nhưng điều này:

import scala.collections.JavaConversions._ 
(1 to 20).map { _ => bm(1000) { seq.subList(100,200) } }.sum/20 

làm từ 12 đến 15 triệu! Được cấp, đây không phải là thứ tự độ lớn, giống như trong trường hợp mảng, nhưng (1) không có sự xử lý đặc biệt nào về nguyên thủy ở đây, vì vậy điều này hoàn toàn tầm thường để thực hiện bằng cách sử dụng công cụ chuẩn java, và (2) bộ sưu tập là bất biến ... khó có thể trả lại tham chiếu đến một dải chỉ mục ???

+1

Bạn đã thấy mã phía sau chúng chưa? – Vale

+0

@Vale vâng, tôi có. Bạn đã đọc câu hỏi chưa? ;) – Dima

+1

Tôi đã làm, nhưng không thể tìm thấy dòng mà bạn nói bạn đã làm. Tôi có thể không giỏi đọc hiểu. – Vale

Trả lời

2

Nó đã được sửa trong scala 2.12.

+10

Yeah ... Bởi tôi: D – Dima

Các vấn đề liên quan