2012-02-17 31 views
13

Tôi hiện đang sử dụng rộng rãi mẫu kiểu lớp là các phần có liên quan đến hiệu suất của mã của tôi. Tôi đã tạo ra ít nhất hai nguồn tiềm năng không hiệu quả.Tác động hiệu suất của việc sử dụng mẫu kiểu lớp trong Scala

  1. Các tham số ngầm được truyền qua cuộc gọi tin nhắn. Tôi không biết liệu điều này có thực sự xảy ra hay không. Có thể scalac đơn giản có thể chèn các tham số ngầm định mà chúng được sử dụng và loại bỏ chúng khỏi chữ ký phương thức. Điều này có thể là không thể trong trường hợp bạn chèn các tham số ngầm theo cách thủ công, vì chúng có thể được giải quyết chỉ khi chạy. Tối ưu hóa nào áp dụng liên quan đến việc truyền tham số ẩn?

  2. Nếu thể loại lớp loại được cung cấp bởi def (trái với số val), đối tượng phải được tạo lại trên mọi lời gọi của "phương pháp được phân loại". Vấn đề này có thể được áp dụng bởi JVM, điều này có thể tối ưu hóa việc tạo đối tượng. Vấn đề này cũng có thể được áp dụng bởi scalac bằng cách sử dụng lại các đối tượng này. Tối ưu hóa nào áp dụng liên quan đến việc tạo ra các đối tượng tham số ngầm định?

Và dĩ nhiên có thể có thêm nguồn không hiệu quả khi áp dụng loại lớp mẫu. Xin vui lòng cho tôi biết về họ.

Trả lời

8

Nếu bạn thực sự quan tâm về cách viết mã siêu hiệu suất cao (và bạn có thể nghĩ bạn làm nhưng phải rất sai về điều này) sau đó typeclasses sẽ gây ra một số đau đớn vì những lý do sau đây:

  • Nhiều thêm phương pháp ảo gọi
  • đấm bốc có khả năng nguyên thủy (ví dụ nếu sử dụng typeclasses scalaz cho monoids vv)
  • Object sáng tạo qua def đó là cần thiết bởi vì chức năng không thể para meterized
  • Object sáng tạo để truy cập các phương pháp "pimped"

Khi chạy, JVM có thể tối ưu hóa một số các sáng tạo sai đi (ví dụ việc tạo một số MA chỉ cần gọi <*>), nhưng scalac không làm được gì nhiều để trợ giúp. Bạn có thể thấy điều này một cách tầm thường bằng cách biên dịch một số mã sử dụng typeclasses và sử dụng -Xprint:icode làm đối số.

Dưới đây là một ví dụ:

import scalaz._; import Scalaz._ 
object TC { 
    def main(args: Array[String]) { 
    println((args(0).parseInt.liftFailNel |@| args(1).parseInt.liftFailNel)(_ |+| _)) 
    } 
} 

Và đây là icode:

final object TC extends java.lang.Object with ScalaObject { 
    def main(args: Array[java.lang.String]): Unit = scala.this.Predef.println(scalaz.this.Scalaz.ValidationMA(scalaz.this.Scalaz.StringTo(args.apply(0)).parseInt().liftFailNel()).|@|(scalaz.this.Scalaz.StringTo(args.apply(1)).parseInt().liftFailNel()).apply({ 
    (new anonymous class TC$$anonfun$main$1(): Function2) 
}, scalaz.this.Functor.ValidationFunctor(), scalaz.this.Apply.ValidationApply(scalaz.this.Semigroup.NonEmptyListSemigroup()))); 
def this(): object TC = { 
    TC.super.this(); 
() 
} 
}; 
@SerialVersionUID(0) final <synthetic> class TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$2 extends scala.runtime.AbstractFunction0 with Serializable { 
    final def apply(): Int = TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$2.this.v1$1; 
    final <bridge> def apply(): java.lang.Object = scala.Int.box(TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$2.this.apply()); 
    <synthetic> <paramaccessor> private[this] val v1$1: Int = _; 
    def this($outer: anonymous class TC$$anonfun$main$1, v1$1: Int): anonymous class TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$2 = { 
    TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$2.this.v1$1 = v1$1; 
    TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$2.super.this(); 
    () 
    } 
}; 
@SerialVersionUID(0) final <synthetic> class TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1 extends scala.runtime.AbstractFunction0$mcI$sp with Serializable { 
    final def apply(): Int = TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1.this.apply$mcI$sp(); 
    <specialized> def apply$mcI$sp(): Int = TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1.this.v2$1; 
    final <bridge> def apply(): java.lang.Object = scala.Int.box(TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1.this.apply()); 
    <synthetic> <paramaccessor> private[this] val v2$1: Int = _; 
    def this($outer: anonymous class TC$$anonfun$main$1, v2$1: Int): anonymous class TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1 = { 
    TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1.this.v2$1 = v2$1; 
    TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1.super.this(); 
() 
    } 
}; 
@SerialVersionUID(0) final <synthetic> class TC$$anonfun$main$1 extends scala.runtime.AbstractFunction2$mcIII$sp with Serializable { 
    final def apply(x$1: Int, x$2: Int): Int = TC$$anonfun$main$1.this.apply$mcIII$sp(x$1, x$2); 
    <specialized> def apply$mcIII$sp(v1$1: Int, v2$1: Int): Int = scala.Int.unbox(scalaz.this.Scalaz.mkIdentity({ 
(new anonymous class TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$2(TC$$anonfun$main$1.this, v1$1): Function0) 
}).|+|({ 
    (new anonymous class TC$$anonfun$main$1$$anonfun$apply$mcIII$sp$1(TC$$anonfun$main$1.this, v2$1): Function0) 
}, scalaz.this.Semigroup.IntSemigroup())); 
final <bridge> def apply(v1: java.lang.Object, v2: java.lang.Object): java.lang.Object = scala.Int.box(TC$$anonfun$main$1.this.apply(scala.Int.unbox(v1), scala.Int.unbox(v2))); 
    def this(): anonymous class TC$$anonfun$main$1 = { 
    TC$$anonfun$main$1.super.this(); 
    () 
    } 
} 

}

Bạn có thể thấy có một số tiền rất lớn của các đối tượng sáng tạo xảy ra ở đây

+0

Vì vậy, một gợi ý tôi đọc từ câu trả lời của bạn có thể là để thay thế 'scalaz.Monoid', mà tôi thực sự đang sử dụng, bởi một phiên bản riêng với SPE cialization? Mặc dù chuyên môn dường như rất lỗi ... Ngay cả 'Numeric' không phải là chuyên ngành. – ziggystar

+0

Tôi sẽ chỉ đạo rõ ràng về chuyên môn tbh. Nếu tôi đã ở trong đôi giày của bạn, tôi sẽ muốn được * rất, rất chắc chắn * rằng tôi đã cần phải ép từng giọt hiệu suất cuối cùng ra khỏi mã.Điều gì làm cho bạn chắc chắn rằng bạn làm gì? Nếu mọi thứ phải gần với kim loại, thì tôi sẽ nói rằng bạn sẽ phải quay lại bộ sưu tập có thể thay đổi, mã bắt buộc và trong khi vòng lặp. Có thực sự là không có câu trả lời khác –

+0

Nó không thực sự phải càng nhanh càng tốt. Nhưng tôi không muốn thực hiện tác động của boxing. Tôi hiện đang sử dụng mảng nguyên thủy (không có đột biến chúng). Liên quan đến vấn đề, có thể giữ mã rất chung chung để áp dụng cho một không gian vấn đề lớn (tôi thậm chí còn sử dụng các vòng đại số như là một trừu tượng). Hiện tại tôi không muốn quyết định giữa hiệu suất (như boxing tham gia một hit 10x) và trừu tượng; nó không phải là một sự lựa chọn dễ dàng và tôi tự hỏi làm thế nào đến nay tôi có thể đi với lấy cả hai. – ziggystar

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