通過對比靜態調用與類反射調用方法的效率,來了解現代框架中大量應用的反射調用對性能的影響程度。以便在系統架構中對性能與開發便利性之間進行權衡與取捨。
代碼1:
- /**
- *
- */
- package test;
- import java.lang.reflect.Method;
- /**
- * @author jetlong
- *
- */
- public class PerformanceTest {
- /**
- * @param args
- */
- public static void main(String[] args) throws Exception {
- int testTime = 10000000;
- PerformanceTest test = new PerformanceTest();
- String msg = "this is test message";
- long bTime = System.currentTimeMillis();
- for(int i=0; i<testTime; i++) {
- test.takeAction(msg);
- }
- long eTime = System.currentTimeMillis();
- System.out.println(eTime - bTime);
- Method method = test.getClass().getMethod("takeAction", String.class);
- bTime = System.currentTimeMillis();
- for(int i=0; i<testTime; i++) {
- method.invoke(test, msg);
- }
- eTime = System.currentTimeMillis();
- System.out.println(eTime - bTime);
- }
- public int takeAction(String msg) {
- return (msg.length() * (int)(System.currentTimeMillis() % 100000));
- }
- }
上述方法有緩存方法
在上述1千萬次的測試情況下,直接調用與反射調用的相差一倍左右。
764
1516
819
1466
881
1505
其實這種測試結果與測試方法有關,在性能評估中,應評估反射浪費的性能所佔的比例,如果是複雜方法,也許這個比例就較低。
如果使用較爲簡單的調用方法測試(比如單位時鐘週期可以完成的操作),則反射所消耗的時間比例是驚人的。
代碼2:(不緩存查詢到的被調方法)
- /**
- *
- */
- package test;
- import java.lang.reflect.Method;
- /**
- * @author jetlong
- *
- */
- public class PerformanceTest {
- /**
- * @param args
- */
- public static void main(String[] args) throws Exception {
- int testTime = 10000000;
- PerformanceTest test = new PerformanceTest();
- String msg = "this is test message";
- long bTime = System.currentTimeMillis();
- for(int i=0; i<testTime; i++) {
- test.takeAction(msg);
- }
- long eTime = System.currentTimeMillis();
- System.out.println(eTime - bTime);
- bTime = System.currentTimeMillis();
- for(int i=0; i<testTime; i++) {
- Method method = test.getClass().getMethod("takeAction", String.class);
- method.invoke(test, msg);
- }
- eTime = System.currentTimeMillis();
- System.out.println(eTime - bTime);
- }
- public int takeAction(String msg) {
- return (msg.length() * (int)(System.currentTimeMillis() % 100000));
- }
- }
測試結果:
930
5369
898
5052
885
5346
889
4992
對比代碼1的測試結果,沒有緩存被調用方法的情況下,性能損失更爲嚴重。
而考慮在框架級實現中,緩存是通過map等機制進行的,那麼在獲取緩存時的時間成本也要計算在內,則整體性能對比將在上述兩個測試之間。
考慮目前的計算機系統的速度,應用開發已經不在那麼介意性能,而更爲注重系統的可維護性和擴展性以及快速開發效率上。上述的測試結果是在一千萬次的測試基礎上產生的。而在通常的一次業務請求中,反射使用的次數應該是非常少的,只在框架級基礎上被使用,在一個高負載的系統中,業務處理的性能將是關鍵點,而不在於使用的這些反射所帶來的性能影響上。而使用反射所帶來的開發便利與可維護性可擴展性的提升所帶來的價值,是遠遠高於其所損耗的性能的。
又回想起原來在某個所謂高性能項目中通過減少反射來提高性能的做法,現在想來,比較愚蠢。這說明前期的測試工作沒有到位,而帶來這樣的結論偏差,從而導致了開發與維護的不便,而且極大地影響了開發速度。
其實那個系統的大部分性能瓶頸都是在數據庫上,大部分的業務處理都是在數據庫中進行的,在項目後面的性能測試中發現,WEB服務器的負載非常低,遠遠低於數據庫,大部分的操作都是在等待數據庫的返回。
前期某些推論既沒有經過驗證,也沒有相關的使用經驗來支持此推論,是導致這種錯誤的根源。在將來的架構設計工作與框架選型要加強這方面的評估工作,來達到性能與開發效率間的最佳平衡。