2015-01-12 11 views
5

Jak wszyscy wiecie, możliwe jest pobranie metody z Reflection i wywołanie jej za pomocą zwróconej instancji Method.Czy wykonanie metody pobranej przez odbicie trwa dłużej?

Moje pytanie jest jednak; po pobraniu przez Reflection i raz wywołać Method będzie wydajność metody będzie wolniejsza niż normalny sposób wywoływania metody?

Na przykład:

import java.lang.reflect.Method; 

public class ReflectionTest { 

    private static Method test; 

    public ReflectionTest() throws Exception { 
     test = this.getClass().getMethod("testMethod", null); 
    } 

    public void testMethod() { 
     //execute code here 
    } 

    public static void main(String[] args) throws Exception { 
     ReflectionTest rt = new ReflectionTest(); 
     for (int i = 0; i < 1000; i++) { 
      rt.test.invoke(null, null); 
     } 

     for (int i = 0; i < 1000; i++) { 
      rt.testMethod(); 
     } 
    } 
} 

Pytam tego powodu Robię układ zdarzeń, które w momencie rejestracji słuchacza skanuje adnotacji. Metody są umieszczane na mapie, a następnie wykonywane za każdym razem, gdy wystąpi zdarzenie o wymaganym typie parametru. Nie wiem, czy jest wystarczająco wydajna, na przykład w grze.

+1

może nie na egzekucji, być może w trakcie pobierania? – DnR

+0

Sądzę, że jeśli będę uważał z ilością pobrań, które robię, to nie powinno to mieć zbyt dużego wpływu na wydajność? – Limnic

+0

pozwala czekać na odpowiedź pro: D – DnR

Odpowiedz

3

Korzystanie z metody bez refleksji jest o rząd wielkości szybsze. Testowałem go jak

public static void main(String[] args) throws Exception { 
    ReflectionTest rt = new ReflectionTest(); 
    // Warm up 
    for (int i = 0; i < 100; i++) { 
     test.invoke(rt, null); 
    } 
    for (int i = 0; i < 100; i++) { 
     rt.testMethod(); 
    } 

    long start = System.nanoTime(); 
    for (int i = 0; i < 10000; i++) { 
     test.invoke(rt, null); 
    } 
    long end = Math.abs((start - System.nanoTime())/1000); 
    start = System.nanoTime(); 
    for (int i = 0; i < 10000; i++) { 
     rt.testMethod(); 
    } 
    long end2 = Math.abs((start - System.nanoTime())/1000); 
    System.out.printf("%d %d%n", end, end2); 
} 

ja też przeniósł test do pola static więc to skompilować i uruchomić

private static Method test; 
static { 
    try { 
     test = ReflectionTest.class.getMethod("testMethod"); 
    } catch (NoSuchMethodException e) { 
     e.printStackTrace(); 
    } catch (SecurityException e) { 
     e.printStackTrace(); 
    } 
} 

mam dość spójną różnicę (lub wyjście spójne) z

4526 606 

Co oznacza, że ​​w przypadku wywołania inwokacji 10000 odbicie jest ~ 7 razy wolniejsze niż wywołanie bezpośrednie.

+0

Hmm. To rozczarowuje :(Naprawdę podoba mi się sposób działania mojego systemu eventowego Ten sam test zabrał na mój komputer '1740 228. Czy myślisz, że powinienem utrzymywać system wydarzeń tak jak jest, czy masz jakieś sugestie na lepsze wydarzenie? system? – Limnic

+0

Szczerze mówiąc, myślę, że jest to prawdopodobnie przypadek przedwczesnej optymalizacji, a dodatkowa elastyczność, jaką daje refleks, wydaje się być warta kary, a jeśli jest jakaś krytyczna ścieżka, to możesz ją zoptymalizować, gdy ją znajdziesz .. –

+0

@ Limnic - jak czy spodziewasz się, że ktoś odpowie na to ... chyba że * widział * kod twojego systemu zdarzeń? I tak, "przedwczesną optymalizację" !! –

2

@Elliot Frisch's zapewnia jednoznaczne dowody, że używanie Method.invoke() jest wolniejsze.

Można się tego spodziewać, ponieważ wersja odblaskowa wymaga dodatkowej pracy; na przykład

  • tworzenie i inicjalizacji z układu zawierającego varags,
  • sprawdzenie długości tablicy, a
  • odlewania argumentów w tablicy z Object do odpowiednich typów parametrów.

Jest możliwe, że JIT mógłby mógł zoptymalizować to w niektórych przypadkach ...


1 - OK ... niejednoznaczne. Benchmark jest wątpliwy, ponieważ nie zwraca należytej uwagi na ewentualne anomalie związane z rozgrzewaniem JVM.

Powiązane problemy