乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      Java性能設(shè)計(jì)

       codeman 2006-09-11
      很多程序員在一開始并不注重性能的設(shè)計(jì),只有當(dāng)系統(tǒng)交付運(yùn)行時,才 發(fā)現(xiàn)問題并且開始解決這一問題,但往往這只能挽救一點(diǎn)點(diǎn)。性能的管理應(yīng)該一開始 就被整合到設(shè)計(jì)和開發(fā)當(dāng)中去。

      最普遍的問題就是臨時對象大量經(jīng)常的創(chuàng)建,這為性能埋下隱患。

      性能的問題來自很多原因,最容易解決的可能是:你選擇了不好的算法來進(jìn)行計(jì)算,如 用冒泡法來排序巨量數(shù)據(jù),或者你每次使用數(shù)據(jù)時都要反復(fù)計(jì)算一次,這應(yīng)該使用Cache。

      你能很容易的使用工具(如Borland的Optimizeit)或壓力測試發(fā)現(xiàn)這些問題, 一旦發(fā)現(xiàn),就能夠立即被糾正,但是很多Java的性能問題隱藏得更深,難于修改源碼就能糾正, 如程序組件的接口設(shè)計(jì)。

      現(xiàn)在我們倡導(dǎo)面向?qū)ο蟮慕M件可復(fù)用設(shè)計(jì),無疑這樣設(shè)計(jì)的優(yōu)點(diǎn)是巨大的, 但是也要注意到對性能的影響。

      一個java性能設(shè)計(jì)原則是,避免不必要的對象創(chuàng)建,對象的創(chuàng)建是非常耗時的, 所以你要避免不必要的臨時或過多的對象創(chuàng)建,

      String是程序中最主要創(chuàng)建的對象,因?yàn)镾tring是不變的,如果String長度被修改 將導(dǎo)致String對象再次創(chuàng)建,所以對性能有所注意的一般人就是盡量回避使用String, 但是這幾乎是不可能的。

       

      接口參數(shù)設(shè)計(jì)

      舉例 MailBot:
      MailBot郵件系統(tǒng)的有一個Header數(shù)據(jù),它是character buffer,需要對這個character buffer 進(jìn)行分析比較,那么你要做一個類Matcher,在這個類中你將Header數(shù)據(jù)讀入然后配比, 一個不好的做法是:

      public class BadRegExpMatcher {
        public BadRegExpMatcher(String regExp);

        /** Attempts to match the specified regular expression against the input     text, returning the matched text if possible or null if not
        */
        public String match(String inputText);

      }

      這個BadRegExpMatche要求入口參數(shù)是String ,那么如果MailBot要調(diào)用他,必須自己做一個 character buffer到String的轉(zhuǎn)換:

      BadRegExpMatcher dateMatcher = new BadRegExpMatcher(...);

      while (...) { ...

      //產(chǎn)生新的String
      String headerLine = new String(myBuffer, thisHeaderStart, thisHeaderEnd-thisHeaderStart);

      String result = dateMatcher.match(headerLine);

      if (result == null) { ... }

      }

      很明顯,這里這個由于接口不一致導(dǎo)致了多余的對象String headerline的創(chuàng)建,這是不能允許的, 應(yīng)該將Matcher的接口設(shè)計(jì)成能夠接納character buffer,當(dāng)然為通用性,也應(yīng)該提供String的 接口參數(shù):

      class BetterRegExpMatcher {
        public BetterRegExpMatcher(...);

        /** 提供多個接口參數(shù)的match方法
        Provide matchers for multiple formats of input -- String,
        character array,   and subset of character array. Return
        -1 if no match was made; return offset of match start if
        a match was made. */
       
        public int match(String inputText);
        public int match(char[] inputText);
        public int match(char[] inputText, int offset, int length);

        /** Get the next match against the input text, if any */
        public int getNextMatch();

        public int getMatchLength();

        public String getMatchText();
      }

      很明顯BetterRegExpMatcher的運(yùn)行速度將比前面BadRegExpMatcher運(yùn)行速度快。

      因?yàn)樵谀阋呀?jīng)寫好代碼的情況下,你比較難于更改一個類的接口參數(shù),那就應(yīng)該在寫程序之前多 多考慮你這些接口參數(shù)的類型設(shè)定,最好有一個通盤的接口類型規(guī)定。

       

      減少對象的創(chuàng)建

      臨時對象是那些有很短的生命周期,通常服務(wù)一些非十分有用的目標(biāo),程序員通常使用臨時對象作為 數(shù)據(jù)混合包傳送或者返回,為避免上述示例哪些轉(zhuǎn)換接口對象的構(gòu)造,你應(yīng)該巧妙的避免創(chuàng)造這些臨時 對象,以防止給你的程序留下性能的陰影。

      上述示例說明性能問題在于String對象,但是String在對象創(chuàng)建中又是如此的普遍,String是不變的,一旦賦值,就不會變化,不少程序員 認(rèn)為不變的東西總是會導(dǎo)致壞的性能,其實(shí)它并不是這么簡單,實(shí)際上,性能好壞在于你如何使用這個東西。

      對于經(jīng)常需要變化的String,很明顯使用Stringbuffer來代替。

      舉例:
      看下面兩種實(shí)現(xiàn):

      public class Component {
        ...
        protected Rectangle myBounds;
        public Rectangle getBounds() { return myBounds; }
      }



      public class Component {
        public Rectangle getBounds() {
          return new Rectangle(myBounds.x, myBounds.y, myBounds.height,    
                        myBounds.width);
        }
      }

      當(dāng)使用Component分別對應(yīng)有如下兩種:

      Rectangle r = component.getBounds();

      ...

      r.height *= 2;


      int x = component.getBounds().x;
      int y = component.getBounds().y;
      int h = component.getBounds().height;
      int w = component.getBounds().width;

      第一種使用方式缺點(diǎn),r.height的使用已經(jīng)脫離component,容易引起溝通上的誤解,因?yàn)?nbsp;Rectangle變化必須涉及component內(nèi)容重新刷新,萬一其它程序員不知道這個規(guī)則,修改 r.height(乘2),將不會去刷新component,

      第二中方式是個提高,迫使componenet和其部件跟隨在一起。但是帶來問題是:創(chuàng)建了 四個臨時對象。

      改進(jìn)辦法是,在第一種的基礎(chǔ)上,在Commponent中增加

      public int getX() { return myBounds.x; }
      public int getY() { return myBounds.y; }
      public int getHeight() { return myBounds.height; }
      public int getWidth() { return myBounds.width; }

      這樣調(diào)用變成:
      int x = component.getX();
      int y = component.getY();
      int h = component.getHeight();
      int w = component.getWidth();

      兩全其美了不是?

      這就是減少創(chuàng)建對象技巧之一: 增加finer-grained輔助功能

      第二種技巧是:Exploit mutability

      上例還有一種實(shí)現(xiàn)方式:

      public Rectangle getBounds(Rectangle returnVal) {
        returnVal.x = myBounds.x;
        returnVal.y = myBounds.y;
        returnVal.height = myBounds.height;
        returnVal.width = myBounds.width;
        return returnVal;

      }

      多巧妙,把Rectangle作為參數(shù)傳進(jìn)來修改一下再送出去。

      技巧3是 融合變和不變于一身。

      總結(jié)上面一些例子,發(fā)現(xiàn)一個規(guī)律:臨時對象產(chǎn)生是在這種情況下產(chǎn)生的: 不變的要轉(zhuǎn)換成可變的。那么針對這個根本原因我們設(shè)計(jì)出各取所需的方案。

      以下例說明:

      Point是不變的,我們繼承它,定義一個可變的子類。

      public class Point {
        protected int x, y;
        public Point(int x, int y) { this.x = x; this.y = y; }
        public final int getX() { return x; }
        public final int getY() { return y; }
      }

      public class MutablePoint extends Point {
        public final void setX(int x) { this.x = x; }
        public final void setY(int y) { this.y = y; }
      }

      這樣,可變的需求和不可變的需求各自滿足,分別調(diào)用。

      public class Shape {
        private MutablePoint myLocation;

        //返回可變的
        public Shape(int x, int y) {
          myLocation = new MutablePoint(x, y);
        }

        //返回不變的
        public Point getLocation() { return (Point) myLocation; } }

       

      遠(yuǎn)程接口

      在分布式應(yīng)用中,性能也是相當(dāng)重要的,這里介紹如何通過檢查class的接口 能簡單預(yù)知分布式應(yīng)用中的性能問題。

      在分布式應(yīng)用中,一個在這個系統(tǒng)中運(yùn)行的對象能夠調(diào)用另外一個系統(tǒng)的對象的方法,這是通過很多 內(nèi)部機(jī)制來實(shí)現(xiàn)將遠(yuǎn)程對象貌似本地對象的,為了發(fā)現(xiàn)遠(yuǎn)程對象,你首先必須發(fā)現(xiàn)它,這是通過一種 名稱目錄服務(wù)機(jī)制,比如RMO的注冊,JNDO和CORBA的名稱服務(wù)。

      當(dāng)你通過目錄服務(wù)得到一個遠(yuǎn)程的對象,你不是得到一個實(shí)際的指向,而是一個和遠(yuǎn)程行為一樣的stub對象的 指向, 當(dāng)你調(diào)用stub對象的一個方法時,這個得marshal這個方法參數(shù):也就是轉(zhuǎn)換成byte-stream,這類似 于序列化,這個stub對象通過網(wǎng)絡(luò)將marshal后的參數(shù)發(fā)送給skeleton對象,后者負(fù)責(zé)unmarshal這些參數(shù)然后 調(diào)用真正實(shí)際的你要調(diào)用的遠(yuǎn)程方法,然后,這個方法返回一個值給skeleton,再逐個沿著剛才路線返回, 一個簡單方法要做這么多工作啊。

      很顯然,遠(yuǎn)程方法調(diào)用要比本地方法調(diào)用來得耗時昂貴。

      上面返回情況是是指返回原始型primitive,如果返回的是對象,怎么辦?如果這個對象支持遠(yuǎn)程調(diào)用,它又會通過查詢創(chuàng)造一個stub和skeleton對象,這又是耗時的;如果這個對象不支持遠(yuǎn)程調(diào)用,那么所有的對象的字段和任何涉及引用的對象都要被marshal,這也是 相當(dāng)耗時的。

      由此可見,一個不好的遠(yuǎn)程接口設(shè)計(jì)將完全扼殺程序的性能,為了避免網(wǎng)絡(luò)開銷,設(shè)計(jì)一次 遠(yuǎn)程調(diào)用返回多值總比多次調(diào)用,每次只返回一個值要好得多。

      還有提防在不需要返回遠(yuǎn)程對象時,返回一個遠(yuǎn)程對象。不要傳遞很復(fù)雜不必要的對象給遠(yuǎn)程。

      假設(shè)遠(yuǎn)程服務(wù)器有一個目錄列表對象,每個目錄項(xiàng)目中包含姓名 電話號碼 和郵件地址等值, 下列程序:

      public interface Directory extends Remote {
        DirectoryEntry[] getEntries();
        void addEntry(DirectoryEntry entry);
        void removeEntry(DirectoryEntry entry);

      }

      public interface DirectoryEntry extends Remote {
        String getName();
        String getPhoneNumber();
        String getEmailAddress();

      }

      這樣設(shè)計(jì)導(dǎo)致結(jié)果是,當(dāng)我需要一個姓名值時,首先要獲得Directory 對象,再獲得DirectoryEntry, 獲得DirectoryEntry才能獲得getName,這么來來回回,需要多少次網(wǎng)絡(luò)開銷啊。

      public interface Directory extends Remote {
        String[] getNames();
        DirectoryEntry[] getEntries();

        //加入這個方法
        DirectoryEntry getEntryByName(String name);
        void addEntry(DirectoryEntry entry);
        void removeEntry(DirectoryEntry entry);

      }

      這樣直接在Directory加上DirectoryEntry和getNames(),一次網(wǎng)絡(luò)開銷就全部解決。

      當(dāng)然這樣的解決方案是完全建立在對分布式應(yīng)用原理了解的基礎(chǔ)上。

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多