2016-06-18 12 views
6

tôi gặp phải vấn đề này trong khi làm bài tập về nhà từ Coursera "chuyên môn hóa scala" (điều này được đơn giản hóa phiên bản và không chứa bất kỳ thông tin chi tiết bài tập ở nhà, nó chỉ là mảng traversal)Scala mô hình phù hợp với hiệu suất

val chars: Array[Char] = some array 

def fun1(idx:Int):Int = { 
    some code here (including the stop condition) 

    val c = chars(idx) 
    c match{ 
     case '(' => fun1(idx+1) 
     case _ => fun1(idx+1) 
    } 

} 

Mã này là 4 lần chậm hơn so với

def fun2(idx: Int):Int = { 
    some code here (including the stop condition) 

    val c = chars(idx) 
    (c == '(') match{ 
     case true => fun2(idx+1) 
     case _ => fun2(idx+1) 
    } 
} 

Tất cả tôi đang làm là thay đổi mô hình phù hợp với (tôi đang chạy nó bằng cách sử ScalMeter vì vậy tôi tin vào số liệu thống kê).

Có ai có thể giải thích hành vi này không?

Trả lời

2

Tôi chỉ có thể xác nhận rằng match đầu tiên chậm hơn ~ 50%, chứ không phải 4x (2.11.8). Dù sao, nếu bạn nhìn vào bytecode, bạn có thể thấy rằng match đầu tiên được dịch sang hướng dẫn tableswitch, thường được sử dụng cho câu lệnh Java switch với nhiều lựa chọn và về cơ bản là goto tra cứu, trong khi thứ hai được dịch sang if. Vì vậy, thứ hai match chỉ đơn giản là:

if (c == '(') fun2(idx+1) else fun2(idx+1) 
0

Cập nhật dưới đây là sai (phần lớn thời gian trong những thử nghiệm đã được chi tiêu tạo ra các dữ liệu, do sự khác biệt trong lần traversal thực tế là không đáng chú ý Chạy benchmark này giống nhau. với đầu vào liên tục hiển thị ~ 125ms trên 100 triệu mục nhập cho case ')' trường hợp so với ~ 35ms đối với trường hợp khác.)

Tôi không thấy sự khác biệt mà bạn mô tả. Không chắc chắn cách ScalaMeter hiện nó, nhưng chạy nó trong repl (sau khi để "hâm nóng" bằng cách chạy "khô" một vài lần), tôi nhận được hầu như cùng một hiệu suất:

def func(s: Seq[Char], idx: Int): String = 
    if(idx == s.length) "foo" else s(idx) match { 
    case ')' => func(s, idx+1) 
    case _ => func(s, idx+1) 
    } 

def func1(s: Seq[Char], idx: Int): String = 
    if(idx == s.length) "foo" else (s(idx) == '(') match { 
    case true => func(s, idx+1) 
    case _ => func(s, idx+1) 
    } 

import scala.util.Random 
def randy = Stream.continually(Random.nextPrintableChar) 


def doit(n: Int)(f: (Seq[Char], Int) => String) = { 
val start = System.currentTimeMillis;  
f(randy.take(n).toIndexedSeq, 0); 
System.currentTimeMillis - start 
} 


scala> doit(1000000)(func) 
res9: Long = 231 

scala> doit(1000000)(func1) 
res10: Long = 238 

scala> doit(1000000)(func) 
res11: Long = 234 

scala> doit(1000000)(func1) 
res12: Long = 201 

vv Như bạn có thể thấy, không có sự khác biệt đáng kể.

+0

Tôi nghi ngờ rằng đây là bất kỳ điều gì gần phương pháp đo điểm chuẩn hợp lệ. ScalaMeter không giống như vài chục warmups cho đến khi kết quả ổn định. Bạn thậm chí không kiểm tra bằng cách sử dụng cùng một dữ liệu. –

+0

Đúng, không phải cùng một dữ liệu. Nhưng tôi nhận được kết quả khá gần giữa các lần chạy. Stddev cực kỳ thấp, điều này gợi ý rằng nếu tôi sử dụng cùng một dữ liệu, tôi sẽ không thấy nhiều sự khác biệt. Như đã đề cập trong câu trả lời, tôi cũng đã làm ấm lên, vì vậy không chắc chắn về điểm chuẩn này bạn thấy "không hợp lệ". Tôi đứng trước những phát hiện của tôi, và thách thức bạn bác bỏ chúng một cách dứt khoát (và tái tạo) nếu bạn có thể. – Dima

+0

Vay các chức năng của bạn, đây là điểm chuẩn với scala meter: https://gist.github.com/lukaszwawrzyk/a2505d5b3083bb72de51b8445fbb9a76 Đưa ra 'thời gian char: 13.172258374999998 ms' và' bool time: 4.739404575 ms'. Nó được thực hiện cho mảng như trong câu hỏi, nếu sử dụng một kết quả seq được lập chỉ mục thực sự gần hơn nhưng không bằng nhau (95 giây so với 80 giây) –

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