<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    IO性能

    Posted on 2010-01-23 21:03 周舒陽(yáng) 閱讀(2967) 評(píng)論(4)  編輯  收藏
    本期Blog原文參見(jiàn):
    http://www.liferay.com/web/shuyang.zhou/blog/-/blogs/io-performance

          IO操作幾乎對(duì)于所有的應(yīng)用都是非常重要的,因?yàn)镮O操作非常容易導(dǎo)致性能瓶頸。

          在Java的世界里存在兩大類IO,傳統(tǒng)IO(TIO)和新IO(NIO)。外加一個(gè)即將到來(lái)的增強(qiáng)版的NIO——NIO2(JDK7)。
    NIO(以及NIO2)主要用于在一些特定情況下增強(qiáng)性能、提供更好的操作系統(tǒng)層次IO功能集成,但它們無(wú)法完全替代TIO!在許多情況下TIO仍然是你唯一的選擇。

          今天我們就來(lái)討論一下TIO的性能問(wèn)題。

    IO的性能瓶頸主要分為兩類:
    1. 錯(cuò)誤的使用緩沖(buffer)
    2. 過(guò)度的同步保護(hù)

          我們都知道buffer能夠增加IO的性能,但不是每個(gè)人都知道如何正確的使用buffer,在本文結(jié)束時(shí)我會(huì)給出一些最佳實(shí)踐建議。

    第一部分:
          對(duì)于1,錯(cuò)誤的使用緩沖(buffer),存在兩點(diǎn)非常流行的錯(cuò)誤用法和一個(gè)感念上的誤解
    • a)為內(nèi)存IO類(In-memory IO class)添加緩沖(錯(cuò)誤用法)
    • b)為已添加buffer的IO類再次添加buffer(錯(cuò)誤用法)
    • c)Buffer版的IO類和顯式使用buffer間的關(guān)系(概念上的誤解)
          對(duì)于a),這是非常荒謬的!添加buffer的目的是為了將對(duì)IO設(shè)備的多次訪問(wèn)合并為一次訪問(wèn)從而提高性能,In-memory類(如ByteArrayInput/OutputStream)根本就不會(huì)訪問(wèn)任何IO設(shè)備,所以對(duì)它們添加buffer是完全沒(méi)有必要的。
          對(duì)于b),這是完全多余的!你只需要buffer一次就可以了,多于一次的buffer只會(huì)引入更多的棧調(diào)用和垃圾創(chuàng)建。
          對(duì)于c),這需要多一點(diǎn)解釋:
          從本質(zhì)上講,這兩種做法是要達(dá)到相同的目的,但方法不同,這也導(dǎo)致了它們之間具有巨大的性能差異!
    針對(duì)這一問(wèn)題我做了一個(gè)測(cè)試,比較使用Buffer版的IO類和顯式使用buffer在讀/寫(xiě)文件時(shí)的性能差異。
    下面的測(cè)試結(jié)果顯式了兩者的性能差異:

    讀測(cè)試結(jié)果:(所有數(shù)據(jù)都是在JVM預(yù)熱后取得的,每個(gè)采樣點(diǎn)的時(shí)間是10次讀取操作的總時(shí)間,單位為毫秒)
     文件大小  1K 10K
    100K
    1M
    10M
    100M
    1G
     BufferedInputStream  0  1
     5  53  549  5492  56002
     顯式使用byte[]在FileInputStream上讀取  0  0  1
     10
     113
     1126
     11448




    寫(xiě)測(cè)試結(jié)果:(所有數(shù)據(jù)都是在JVM預(yù)熱后取得的,每個(gè)采樣點(diǎn)的時(shí)間是10次寫(xiě)入操作的總時(shí)間,單位為毫秒)
     文件大小  1K 10K
    100K
    1M
    10M
    100M
    1G
     BufferedOutputStream  0  1
     5  45  472  4793  48794
     顯式使用byte[]在FileOuputStream上寫(xiě)入  0  1  1
     10
     124
     1300
     13138



          為什么會(huì)有如此大的性能差異呢?有兩點(diǎn)原因:
    1. Buffer版的IO類導(dǎo)致很多無(wú)謂的棧調(diào)用(都是裝飾者模式惹得禍decorator pattern)
    2. JDK中所有的Buffer版IO類都是線程安全的,這就意味著它們添加了大量的同步保護(hù)(將在第二部分中詳細(xì)解釋)
          現(xiàn)在你知道了顯式使用buffer要比使用Buffer版的IO類具有更好的性能,所以請(qǐng)盡量多顯式使用buffer,但在兩種特殊情況下你仍然需要Buffer版的IO類:
    • 當(dāng)你在使用第三方庫(kù)時(shí),庫(kù)的api需要IO類作為參數(shù),并且你確定他們內(nèi)部的代碼采用流式方式編碼(非塊式操作),也就是沒(méi)有顯式使用buffer。在不修改他們代碼的前提下,你只能通過(guò)傳入Buffer版的IO類對(duì)象來(lái)提升性能。
    • 另外一種情況就是,如果你很懶,你會(huì)更傾向于使用Buffer版的IO類,因?yàn)樗鼈兡芄?jié)省你幾行代碼(相對(duì)于顯式使用buffer)。
    第二部分:
          對(duì)于2,過(guò)度的同步保護(hù),我指的是JDK的IO包,也就是java.io包。
          我一點(diǎn)也不喜歡這個(gè)包里面的代碼,因?yàn)樗麄兌际蔷€程安全的,也就意味著許多同步保護(hù)。如果我需要同步保護(hù),我會(huì)自己去做,而且我絕不會(huì)去添加任何多余的保護(hù)。但在這一點(diǎn)上JDK的IO包把我逼得無(wú)路可走

          只要你使用JDK的IO包,你就被迫的添加了許多同步保護(hù),即使你完全確定你的代碼運(yùn)行在單一線程的環(huán)境下,你也不能回避這些不必要的保護(hù)。你也許會(huì)好奇的問(wèn),這真的是一個(gè)嚴(yán)重的問(wèn)題嗎?JVM在運(yùn)行時(shí)會(huì)對(duì)弱競(jìng)爭(zhēng)的鎖進(jìn)行優(yōu)化,不是嗎?顯然,它做的優(yōu)化還不到家,讓我們來(lái)看一下性能測(cè)試結(jié)果。

          我翻版了一批JDK IO包中常用的類,這個(gè)翻版完全是API層次的翻版,也就是說(shuō)全部代碼是參照J(rèn)DK IO包的Javadoc寫(xiě)成, 沒(méi)有直接借用JDK的源碼。因?yàn)镴DK源碼大部分使用GPL協(xié)議發(fā)布,而Liferay的代碼采用MIT協(xié)議發(fā)布,為了不引起IP糾紛只好照葫蘆畫(huà)瓢。而實(shí)際上從0開(kāi)始創(chuàng)建這些類一點(diǎn)也不難(僅僅是裝飾者模式而已),只是非常的繁瑣。在我的翻版類中,我移除了全部的同步保護(hù)。而我的測(cè)試也進(jìn)行在單一線程環(huán)境下,所以不用擔(dān)心線程安全的問(wèn)題。

          測(cè)試包含兩部分,第一部分比較原始JDK IO類和我的unsyc版的IO類在讀取內(nèi)存數(shù)據(jù)(In-memory data)時(shí)的性能差異,第二部分比較原始JDK IO類和我的unsyc版的IO類在寫(xiě)入內(nèi)存數(shù)據(jù)(In-memory data)時(shí)的性能差異。之所以采用內(nèi)存數(shù)據(jù)而不是磁盤(pán)數(shù)據(jù)是為了放大同步操作對(duì)整體性能的影響,以便于分析。

    讀測(cè)試結(jié)果:

    寫(xiě)測(cè)試結(jié)果:

          寫(xiě)數(shù)據(jù)的測(cè)試曲線不像讀的那樣平滑,原因在于它內(nèi)部使用了一個(gè)動(dòng)態(tài)增長(zhǎng)的byte[],這導(dǎo)致大量GC活動(dòng)(與上一期Blog中我們討論SB時(shí)看到的問(wèn)題相似)。

          好了,現(xiàn)在你應(yīng)該看到了同步保護(hù)是一項(xiàng)多么沉重的操作。我們?nèi)粘i_(kāi)發(fā)中存在大量局限在方法調(diào)用棧內(nèi)的IO類使用,這些情況都是絕對(duì)發(fā)生在單一線程環(huán)境下的。另外一些時(shí)候,即使IO對(duì)象的引用超出了方法調(diào)用棧的作用域,但我們可以通過(guò)分析得知它仍然只會(huì)被單一線程所訪問(wèn),比如web開(kāi)發(fā)中,針對(duì)一個(gè)request的全部處理一般都是由一個(gè)worker thread來(lái)完成的(除非你的后臺(tái)還有其他的異步服務(wù)線程與worker間交換數(shù)據(jù),但這很少見(jiàn))。對(duì)于這樣的情況,你大可以放心的使用這些unsyc的IO類(com.liferay.portal.kernel.io.unsync)。

    更多關(guān)于unsycIO類的信息請(qǐng)查看Liferay的JIRA鏈接:
    http://issues.liferay.com/browse/LPS-6648

          最后給大家留下一些建議:
    1. 如果可能請(qǐng)盡量顯式使用buffer,而不是使用Buffer版的IO類。
    2. 僅在使用第三方類庫(kù)和你很懶的時(shí)候使用Buffer版的IO類。
    3. 當(dāng)你確定你的代碼運(yùn)行在單一線程環(huán)境下,或者你自己添加了同步保護(hù)時(shí),請(qǐng)使用com.liferay.portal.kernel.io.unsync包中的IO類。它們能大幅提高你的應(yīng)用的IO性能。
          這里我提供了一個(gè)消除了對(duì)Liferay其他類文件依賴的com.liferay.portal.kernel.io.unsync包供大家下載使用。不過(guò)還是推薦大家直接學(xué)習(xí)使用Liferay:)
          http://www.tkk7.com/Files/ShuyangZhou/IOPerformance/src.zip

    Feedback

    # re: IO性能  回復(fù)  更多評(píng)論   

    2010-01-24 01:01 by ilovetjf@163.com
    上面的測(cè)試有些不成立
    1 BufferedInputStream的BufferSize沒(méi)設(shè)置好,以致上面結(jié)果。
    2 實(shí)際的磁盤(pán)IO不能用內(nèi)存來(lái)模擬,而并發(fā)讀寫(xiě)有時(shí)候性能來(lái)看低。

    # re: IO性能  回復(fù)  更多評(píng)論   

    2010-01-24 12:24 by libinsong1204@gmail.com
    學(xué)習(xí)了。謝謝
    希望“Master Your ThreadLocals” 也能翻譯成中文版本

    # re: IO性能  回復(fù)  更多評(píng)論   

    2010-01-24 12:44 by 周舒陽(yáng)
    @ilovetjf@163.com
    1)這不是bufferSize的問(wèn)題,測(cè)試中BufferedInputStream的bufferSize和顯式使用的byte[]的大小相同(8k),這個(gè)測(cè)試不是為了找出多大的bufferSize是最佳大小,而是為了比較兩種使用buffer方式的性能差異。
    2)使用內(nèi)存數(shù)據(jù)是為了放大同步保護(hù)對(duì)性能的影響,在實(shí)際應(yīng)用中大量使用內(nèi)存流的例子隨處可見(jiàn)。比如web應(yīng)用中Etag,minifier,gzip,cache等f(wàn)ilter都是要借助于內(nèi)存流來(lái)處理數(shù)據(jù)的,所以內(nèi)存流性能的重要性一點(diǎn)也不必磁盤(pán)流的低。

    我沒(méi)明白“而并發(fā)讀寫(xiě)有時(shí)候性能來(lái)看低”指的是什么?測(cè)試是在單線程下執(zhí)行(文中有說(shuō)明,請(qǐng)仔細(xì)閱讀)。這里想要證明的是synchronized對(duì)單線程的性能影響,之所以強(qiáng)調(diào)這點(diǎn)是因?yàn)镴VM的相關(guān)資料中有說(shuō)明對(duì)于弱競(jìng)爭(zhēng)的鎖JIT會(huì)進(jìn)行優(yōu)化,而實(shí)際測(cè)試結(jié)果顯示優(yōu)化的并不怎么樣。

    # re: IO性能  回復(fù)  更多評(píng)論   

    2010-01-24 12:47 by 周舒陽(yáng)
    @libinsong1204@gmail.com
    請(qǐng)?jiān)徫业臅r(shí)間相對(duì)比較緊張,稍有空閑我會(huì)繼續(xù)翻譯,請(qǐng)稍等一段時(shí)間。以后我也會(huì)爭(zhēng)取在這里首發(fā)一些針對(duì)中國(guó)讀者的內(nèi)容。(不會(huì)讓大家總是比外國(guó)人慢半拍的)

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     

    posts - 3, comments - 15, trackbacks - 0, articles - 0

    Copyright © 周舒陽(yáng)

    主站蜘蛛池模板: 亚洲av午夜精品无码专区| 搜日本一区二区三区免费高清视频| 国产精品免费久久久久电影网| 四虎影视无码永久免费| 亚洲中文字幕在线乱码| 日韩精品无码免费专区网站| 亚洲自偷自偷偷色无码中文| 暖暖在线视频免费视频| 久久亚洲AV无码精品色午夜 | 亚洲AV无码精品色午夜在线观看| 亚洲五月丁香综合视频| 日韩毛片免费无码无毒视频观看| 亚洲国产日韩在线视频| 久久黄色免费网站| 亚洲熟妇av一区二区三区下载| a免费毛片在线播放| 亚洲成av人片天堂网| 亚洲w码欧洲s码免费| 中文字幕亚洲图片| 久艹视频在线免费观看| 久久精品国产亚洲av麻豆图片| 成人免费无码大片A毛片抽搐 | 国产成人精品免费大全| 久久精品国产亚洲AV网站| 国产曰批免费视频播放免费s| 亚洲一卡2卡3卡4卡乱码 在线| 四虎永久免费影院| 免费精品99久久国产综合精品| 麻豆亚洲AV永久无码精品久久| 成人免费视频一区二区三区| 男人扒开添女人下部免费视频| 亚洲国产精品SSS在线观看AV| 99久久综合国产精品免费| 福利片免费一区二区三区| 男女免费观看在线爽爽爽视频 | 一本色道久久综合亚洲精品高清| 久久免费公开视频| 精品久久久久久久久亚洲偷窥女厕| 5g影院5g天天爽永久免费影院| 久久综合亚洲色一区二区三区| 青青草国产免费久久久91|