2015-12-11 26 views
3

關於Java的等效問題有一些答案,但scala反射(2.11,TypeTags)真的很慢嗎?在http://docs.scala-lang.org/overviews/reflection/overview.html有一個關於它的長篇敘述,這個問題的答案很難提取。Scala TypeTags和性能

我看到很多關於避免反射的建議,也許它有些早於2.11的改進,但如果這樣做效果很好,看起來它可以解決JVM的類型擦除(scala代碼)的衰弱方面。

謝謝!

+1

調用通過反射的方法(在Java或斯卡拉)是不是直接調用該方法,因爲更多的工作已經在運行時千萬要做到慢得多 - 尋找方法,解決它等等,所以如果沒有必要,不要使用反射。 – Jesper

+1

你是在尋找一個對象的方法然後調用它的情況嗎?它如何與類型標籤或類型恢復相關? – matanster

+0

您可以提供一些TypeTags用法的例子,您在哪裏關心性能?一些用法很快,一些很慢,回答討論每種可能的用法似乎很難預料(會太長)。 – Suma

回答

6

讓我們來衡量它。 我創建了簡單的class C,它有一種方法。所有這些方法所做的就是睡眠10毫秒。 讓我們調用反射

  • 直接

  • 內這種方法

    • ,看看哪些是更快的速度有多快它。

      我創建了三個測試。

      測試1.通過反射進行調用。執行時間包括進行設置反射所需的所有工作。 創建runtimeMirror,反映類,創建方法聲明,最後一步 - 執行方法。

      測試2.不要考慮這個準備階段,因爲它可以重複使用。 我們只計算通過反射調用方法的時間。

      測試3.直接調用方法。

      結果:

      從開始思考:在2561ms完成作業得到101(1,5seconds用於設置每個執行)

      Invoke方法反射:在1093ms完成作業得到101(< 1ms的對於設置每個執行)

      沒有反映:在1087ms完成任務拿到101(< 1ms,以適合設置每個執行)

      結論: 設置階段顯着增加執行時間。但是沒有必要在每次執行時執行設置(這類似於類初始化 - 可以完成一次)。因此,如果您以正確的方式使用反射(分離初始階段),它會顯示相關性能並可用於生產。

      源代碼:

      class C { 
           def x = { 
           Thread.sleep(10) 
           1 
           } 
          } 
      
      
          class XYZTest extends FunSpec { 
           def withTime[T](procName: String, f: => T): T = { 
           val start = System.currentTimeMillis() 
           val r = f 
           val end = System.currentTimeMillis() 
           print(s"$procName job done in ${end-start}ms") 
           r 
           } 
      
           describe("SomeTest") { 
           it("rebuild each time") { 
            val s = withTime("Reflection from start : ", (0 to 100). map {x => 
            val ru = scala.reflect.runtime.universe 
            val m = ru.runtimeMirror(getClass.getClassLoader) 
            val im = m.reflect(new C) 
            val methodX = ru.typeOf[C].declaration(ru.TermName("x")).asMethod 
            val mm = im.reflectMethod(methodX) 
            mm().asInstanceOf[Int] 
            }).sum 
            println(s" got $s") 
           } 
           it("invoke each time") { 
            val ru = scala.reflect.runtime.universe 
            val m = ru.runtimeMirror(getClass.getClassLoader) 
            val im = m.reflect(new C) 
            val s = withTime("Invoke method reflection: ", (0 to 100). map {x => 
            val methodX = ru.typeOf[C].declaration(ru.TermName("x")).asMethod 
            val mm = im.reflectMethod(methodX) 
            mm().asInstanceOf[Int] 
            }).sum 
            println(s" got $s") 
           } 
           it("invoke directly") { 
            val c = new C() 
            val s = withTime("No reflection: ", (0 to 100). map {x => 
            c.x 
            }).sum 
            println(s" got $s") 
           } 
           } 
          } 
      
    +0

    這個答案在整體上非常有幫助。任何連接到TypeTags? – matanster

    +0

    'typeOf [C]'使用'TypeTag's。一般來說,這很大程度上取決於你實際需要怎樣處理它們。一些操作將會變得緩慢。 –

    +2

    @ Mr.V。我建議閱讀如何對JVM操作進行基準測試。尤其要看JMH或ScalaMeter。 –