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

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

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

    ivaneeo's blog

    自由的力量,自由的生活。

      BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
      669 Posts :: 0 Stories :: 64 Comments :: 0 Trackbacks

    我從java1.3開始學習java,后來主要用1.4,再后來1.51.6中的很多新特性,都停留在“知道”的狀態,比如nio,雖然據說可以提升性能,但并沒有真正深入使用和測試過,工作操作文件的情況不多,所以關注也不多,即便用到,也還是習慣性的用java.io。今天看到的這篇文章,雖然測試手段非常簡單,所得結論也難免有些片面 ,但依然說明,在順序訪問的時候,NIO的性能相對java.io有很大的提升。

    也許應該update一下自己的知識了,否則就要OUT,或者早已經OUT了。 

    下次操作文件或者寫socket要用NIO了。

    ---

    轉自:http://links.techwebnewsletters.com/ctt?kn=28&m=34038811&r=MzI1Mjc3MDAzOAS2&b=0&j=NTc5NjM4MTAS1&mt=1&rt=0

    以下為翻譯的內容:

    最近我在工作中用到了java i/o相關功能。因為對java.io的了解更多(畢竟面世較早),所以一開始我使用的是java.io包下的類,后來為了測試一下是不是能夠通過NIO提高文件操作性能,于是轉向了java.nio。我得到的結論讓我感到有些震驚,下面是對比測試的一些細節:

       1、在java.io的測試代碼中,我使用RandomAccessFile直接向文件寫數據,并搜索到特定的位置執行記錄的插入、讀取和刪除。

       2、在java.nio的初步測試代碼中,使用FileChannel對象。NIO之所以比java.io更加高效,是因為NIO面向的是data chunks,而java.io基本上是面向byte的。

       3、為了進一步挖掘NIO的能力,我又改用MappedByteBuffer執行測試,這個類是構建在操作系統的虛擬內存機制上的。根據java文檔所說,這個類在性能方面是最好的。

    為了進行測試,我寫了一個模擬員工數據庫的小程序,員工數據的結構如下:

        view plaincopy to clipboardprint?

    class Employee {   

            String last; // the key   

            String first;   

            int id;   

            int zip;   

            boolean employed;   

            String comments;   

        }  

    class Employee {

            String last; // the key

            String first;

            int id;

            int zip;

            boolean employed;

            String comments;

        }

    員工數據寫入文件,并將last name作為索引key,日后可以通過這個key從文件中加載該員工對應的數據。無論使用IONIO還是MappedByteBuffers,首先都需要打開一個RandomAccessFile。以下代碼在用戶的home目錄下創建一個名為employee.ejb的文件,設置為可讀可寫,并初始化對應的ChannelMappedByteBuffer

        view plaincopy to clipboardprint?

    String userHome = System.getProperty("user.home");   

        StringBuffer pathname = new StringBuffer(userHome);   

        pathname.append(File.separator);   

        pathname.append("employees.ejb");   

        java.io.RandomAccessFile journal =   

            new RandomAccessFile(pathname.toString(), "rw");   

        

        //下面這一句是為了NIO   

        java.nio.channels.FileChannel channel = journal.getChannel();   

          

        //下面這兩句是為了使用MappedByteBuffer   

        journal.setLength(PAGE_SIZE);   

        MappedByteBuffer mbb =   

            channel.map(FileChannel.MapMode.READ_WRITE, 0, journal.length() );  

    String userHome = System.getProperty("user.home");

        StringBuffer pathname = new StringBuffer(userHome);

        pathname.append(File.separator);

        pathname.append("employees.ejb");

        java.io.RandomAccessFile journal =

            new RandomAccessFile(pathname.toString(), "rw");

     

        //下面這一句是為了NIO

        java.nio.channels.FileChannel channel = journal.getChannel();

       

        //下面這兩句是為了使用MappedByteBuffer

        journal.setLength(PAGE_SIZE);

        MappedByteBuffer mbb =

            channel.map(FileChannel.MapMode.READ_WRITE, 0, journal.length() );

     

    使用channel.map進行映射后,當該文件被追加了新的數據時,之前的MappedByteBuffer是看不到這些數據的。因為我們想測試讀和寫,所以當文件中追加寫入新的記錄后,需要重新做映射才能使得MappedByteBuffer讀取新數據。為了提高效率,降低重新映射的次數,每次空間不夠的時候,我們將文件擴張特定的大小(比如說1K)以防止每次追加新記錄都要重新映射。

     

    下面是寫入員工記錄的對比測試:

    使用java.io的代碼:

        view plaincopy to clipboardprint?

    public boolean addRecord_IO(Employee emp) {   

            try {   

                byte[] last = emp.last.getBytes();   

                byte[] first = emp.first.getBytes();   

                byte[] comments = emp.comments.getBytes();   

                  

                // Just hard-code the sizes for perfomance   

                int size = 0;   

                size += emp.last.length();   

                size += 4; // strlen - Integer   

                size += emp.first.length();   

                size += 4; // strlen - Integer   

                size += 4; // emp.id - Integer   

                size += 4; // emp.zip - Integer   

                size += 1; // emp.employed - byte   

                size += emp.comments.length();   

                size += 4; // strlen - Integer   

                long offset = getStorageLocation(size);   

                //   

                // Store the record by key and save the offset   

                //   

                if ( offset == -1 ) {   

                    // We need to add to the end of the journal. Seek there   

                    // now only if we're not already there   

                    long currentPos = journal.getFilePointer();   

                    long jounralLen = journal.length();   

                    if ( jounralLen != currentPos )   

                        journal.seek(jounralLen);   

                          

                    offset = jounralLen;   

                }else {   

                    // Seek to the returned insertion point   

                    journal.seek(offset);   

                }   

                // Fist write the header   

                journal.writeByte(1);   

                journal.writeInt(size);   

                // Next write the data   

                journal.writeInt(last.length);   

                journal.write(last);   

                journal.writeInt(first.length);   

                journal.write(first);   

                journal.writeInt(emp.id);   

                journal.writeInt(emp.zip);   

                if ( emp.employed )   

                    journal.writeByte(1);   

                else  

                    journal.writeByte(0);   

                journal.writeInt(comments.length);   

                journal.write(comments);   

                // Next, see if we need to append an empty record if we inserted   

                // this new record at an empty location   

                if ( newEmptyRecordSize != -1 ) {   

                    // Simply write a header   

                    journal.writeByte(0); //inactive record   

                    journal.writeLong(newEmptyRecordSize);   

                }   

                employeeIdx.put(emp.last, offset);   

                return true;   

            }   

            catch ( Exception e ) {   

                e.printStackTrace();   

            }   

            return false;   

        }  

    public boolean addRecord_IO(Employee emp) {

            try {

                byte[] last = emp.last.getBytes();

                byte[] first = emp.first.getBytes();

                byte[] comments = emp.comments.getBytes();

               

                // Just hard-code the sizes for perfomance

                int size = 0;

                size += emp.last.length();

                size += 4; // strlen - Integer

                size += emp.first.length();

                size += 4; // strlen - Integer

                size += 4; // emp.id - Integer

                size += 4; // emp.zip - Integer

                size += 1; // emp.employed - byte

                size += emp.comments.length();

                size += 4; // strlen - Integer

                long offset = getStorageLocation(size);

                //

                // Store the record by key and save the offset

                //

                if ( offset == -1 ) {

                    // We need to add to the end of the journal. Seek there

                    // now only if we're not already there

                    long currentPos = journal.getFilePointer();

                    long jounralLen = journal.length();

                    if ( jounralLen != currentPos )

                        journal.seek(jounralLen);

                       

                    offset = jounralLen;

                }else {

                    // Seek to the returned insertion point

                    journal.seek(offset);

                }

                // Fist write the header

                journal.writeByte(1);

                journal.writeInt(size);

                // Next write the data

                journal.writeInt(last.length);

                journal.write(last);

                journal.writeInt(first.length);

                journal.write(first);

                journal.writeInt(emp.id);

                journal.writeInt(emp.zip);

                if ( emp.employed )

                    journal.writeByte(1);

                else

                    journal.writeByte(0);

                journal.writeInt(comments.length);

                journal.write(comments);

                // Next, see if we need to append an empty record if we inserted

                // this new record at an empty location

                if ( newEmptyRecordSize != -1 ) {

                    // Simply write a header

                    journal.writeByte(0); //inactive record

                    journal.writeLong(newEmptyRecordSize);

                }

                employeeIdx.put(emp.last, offset);

                return true;

            }

            catch ( Exception e ) {

                e.printStackTrace();

            }

            return false;

        } 

     

    使用java.nio的代碼:

        view plaincopy to clipboardprint?

    public boolean addRecord_NIO(Employee emp) {   

            try {   

                data.clear();   

                byte[] last = emp.last.getBytes();   

                byte[] first = emp.first.getBytes();   

                byte[] comments = emp.comments.getBytes();   

                data.putInt(last.length);   

                data.put(last);   

                data.putInt(first.length);   

                data.put(first);   

                data.putInt(emp.id);   

                data.putInt(emp.zip);   

                byte employed = 0;   

                if ( emp.employed )   

                    employed = 1;   

                data.put(employed);   

                data.putInt(comments.length);   

                data.put(comments);   

                data.flip();   

                int dataLen = data.limit();   

                header.clear();   

                header.put((byte)1); // 1=active record   

                header.putInt(dataLen);   

                header.flip();   

                long headerLen = header.limit();   

                int length = (int)(headerLen + dataLen);   

                long offset = getStorageLocation((int)dataLen);   

                //   

                // Store the record by key and save the offset   

                //   

                if ( offset == -1 ) {   

                    // We need to add to the end of the journal. Seek there   

                    // now only if we're not already there   

                    long currentPos = channel.position();   

                    long jounralLen = channel.size();   

                    if ( jounralLen != currentPos )   

                        channel.position(jounralLen);   

                    offset = jounralLen;   

                }   

                else {   

                    // Seek to the returned insertion point   

                    channel.position(offset);   

                }   

                // Fist write the header   

                long written = channel.write(srcs);   

                // Next, see if we need to append an empty record if we inserted   

                // this new record at an empty location   

                if ( newEmptyRecordSize != -1 ) {   

                    // Simply write a header   

                    data.clear();   

                    data.put((byte)0);   

                    data.putInt(newEmptyRecordSize);   

                    data.flip();   

                    channel.write(data);   

                }   

                employeeIdx.put(emp.last, offset);   

                return true;   

            }   

            catch ( Exception e ) {   

                e.printStackTrace();   

            }   

            return false;   

        }  

    public boolean addRecord_NIO(Employee emp) {

            try {

                data.clear();

                byte[] last = emp.last.getBytes();

                byte[] first = emp.first.getBytes();

                byte[] comments = emp.comments.getBytes();

                data.putInt(last.length);

                data.put(last);

                data.putInt(first.length);

                data.put(first);

                data.putInt(emp.id);

                data.putInt(emp.zip);

                byte employed = 0;

                if ( emp.employed )

                    employed = 1;

                data.put(employed);

                data.putInt(comments.length);

                data.put(comments);

                data.flip();

                int dataLen = data.limit();

                header.clear();

                header.put((byte)1); // 1=active record

                header.putInt(dataLen);

                header.flip();

                long headerLen = header.limit();

                int length = (int)(headerLen + dataLen);

                long offset = getStorageLocation((int)dataLen);

                //

                // Store the record by key and save the offset

                //

                if ( offset == -1 ) {

                    // We need to add to the end of the journal. Seek there

                    // now only if we're not already there

                    long currentPos = channel.position();

                    long jounralLen = channel.size();

                    if ( jounralLen != currentPos )

                        channel.position(jounralLen);

                    offset = jounralLen;

                }

                else {

                    // Seek to the returned insertion point

                    channel.position(offset);

                }

                // Fist write the header

                long written = channel.write(srcs);

                // Next, see if we need to append an empty record if we inserted

                // this new record at an empty location

                if ( newEmptyRecordSize != -1 ) {

                    // Simply write a header

                    data.clear();

                    data.put((byte)0);

                    data.putInt(newEmptyRecordSize);

                    data.flip();

                    channel.write(data);

                }

                employeeIdx.put(emp.last, offset);

                return true;

            }

            catch ( Exception e ) {

                e.printStackTrace();

            }

            return false;

        } 

     

    使用MappedByteBuffer的代碼如下:

     

       view plaincopy to clipboardprint?

    public boolean addRecord_MBB(Employee emp) {   

            try {   

                byte[] last = emp.last.getBytes();   

                byte[] first = emp.first.getBytes();   

                byte[] comments = emp.comments.getBytes();   

                int datalen = last.length + first.length + comments.length + 12 + 9;   

                int headerlen = 5;   

                int length = headerlen + datalen;   

                //   

                // Store the record by key and save the offset   

                //   

                long offset = getStorageLocation(datalen);   

                if ( offset == -1 ) {   

                    // We need to add to the end of the journal. Seek there   

                    // now only if we're not already there   

                    long currentPos = mbb.position();   

                    long journalLen = channel.size();   

                    if ( (currentPos+length) >= journalLen ) {   

                        //log("GROWING FILE BY ANOTHER PAGE");   

                        mbb.force();   

                        journal.setLength(journalLen + PAGE_SIZE);   

                        channel = journal.getChannel();   

                        journalLen = channel.size();   

                        mbb = channel.map(FileChannel.MapMode.READ_WRITE, 0, journalLen);   

                        currentPos = mbb.position();   

                    }   

                    if ( currentEnd != currentPos )   

                        mbb.position(currentEnd);   

                    offset = currentEnd;//journalLen;   

                }   

                else {   

                    // Seek to the returned insertion point   

                    mbb.position((int)offset);   

                }   

                // write header   

                mbb.put((byte)1); // 1=active record   

                mbb.putInt(datalen);   

                // write data   

                mbb.putInt(last.length);   

                mbb.put(last);   

                mbb.putInt(first.length);   

                mbb.put(first);   

                mbb.putInt(emp.id);   

                mbb.putInt(emp.zip);   

                byte employed = 0;   

                if ( emp.employed )   

                    employed = 1;   

                mbb.put(employed);   

                mbb.putInt(comments.length);   

                mbb.put(comments);   

                currentEnd += length;   

                // Next, see if we need to append an empty record if we inserted   

                // this new record at an empty location   

                if ( newEmptyRecordSize != -1 ) {   

                    // Simply write a header   

                    mbb.put((byte)0);   

                    mbb.putInt(newEmptyRecordSize);   

                    currentEnd += 5;   

                }   

                employeeIdx.put(emp.last, offset);   

                return true;   

            }   

            catch ( Exception e ) {   

                e.printStackTrace();   

            }   

            return false;   

        }  

    public boolean addRecord_MBB(Employee emp) {

            try {

                byte[] last = emp.last.getBytes();

                byte[] first = emp.first.getBytes();

                byte[] comments = emp.comments.getBytes();

                int datalen = last.length + first.length + comments.length + 12 + 9;

                int headerlen = 5;

                int length = headerlen + datalen;

                //

                // Store the record by key and save the offset

                //

                long offset = getStorageLocation(datalen);

                if ( offset == -1 ) {

                    // We need to add to the end of the journal. Seek there

                    // now only if we're not already there

                    long currentPos = mbb.position();

                    long journalLen = channel.size();

                    if ( (currentPos+length) >= journalLen ) {

                        //log("GROWING FILE BY ANOTHER PAGE");

                        mbb.force();

                        journal.setLength(journalLen + PAGE_SIZE);

                        channel = journal.getChannel();

                        journalLen = channel.size();

                        mbb = channel.map(FileChannel.MapMode.READ_WRITE, 0, journalLen);

                        currentPos = mbb.position();

                    }

                    if ( currentEnd != currentPos )

                        mbb.position(currentEnd);

                    offset = currentEnd;//journalLen;

                }

                else {

                    // Seek to the returned insertion point

                    mbb.position((int)offset);

                }

                // write header

                mbb.put((byte)1); // 1=active record

                mbb.putInt(datalen);

                // write data

                mbb.putInt(last.length);

                mbb.put(last);

                mbb.putInt(first.length);

                mbb.put(first);

                mbb.putInt(emp.id);

                mbb.putInt(emp.zip);

                byte employed = 0;

                if ( emp.employed )

                    employed = 1;

                mbb.put(employed);

                mbb.putInt(comments.length);

                mbb.put(comments);

                currentEnd += length;

                // Next, see if we need to append an empty record if we inserted

                // this new record at an empty location

                if ( newEmptyRecordSize != -1 ) {

                    // Simply write a header

                    mbb.put((byte)0);

                    mbb.putInt(newEmptyRecordSize);

                    currentEnd += 5;

                }

                employeeIdx.put(emp.last, offset);

                return true;

            }

            catch ( Exception e ) {

                e.printStackTrace();

            }

            return false;

        } 

     

    接下來,調用每種方法插入100,000條記錄, 耗時對比如下:

        * With java.io: ~10,000 milliseconds

        * With java.nio: ~2,000 milliseconds

        * With MappedByteBuffer: ~970 milliseconds

     

    使用NIO的性能改善效果非常明顯,使用MappedByteBuffer的性能,更是讓人吃驚。

    使用三種方式讀取數據的性能對比如下:

        * With java.io: ~6,900 milliseconds

        * With java.nio: ~1,400 milliseconds

        * With MappedByteBuffer: ~355 milliseconds

    和寫入的時候情況差不多,NIO有很明顯的性能提升,而MappedByteBuffer則有驚人的高效率。從java.io遷移到nio并使用MappedByteBuffer,通常可以獲得10倍以上的性能提升。

     

    源文檔 <http://blog.csdn.net/sean1203/archive/2010/01/06/5142464.aspx

    posted on 2010-10-14 19:29 ivaneeo 閱讀(1012) 評論(0)  編輯  收藏 所屬分類: java魔力
    主站蜘蛛池模板: 污视频网站在线观看免费| 成人免费午夜无码视频| 亚洲爆乳少妇无码激情| 亚洲Av综合色区无码专区桃色| 日韩激情无码免费毛片| 久久久久高潮毛片免费全部播放| aa午夜免费剧场| 免费精品视频在线| 亚洲精品国产首次亮相| 亚洲w码欧洲s码免费| 亚洲自偷精品视频自拍| 亚洲av中文无码乱人伦在线播放| 亚洲精品无码av天堂| 又黄又爽无遮挡免费视频| 亚洲欧洲成人精品香蕉网| 国产一级一片免费播放i| 好大好硬好爽免费视频| 日韩毛片免费无码无毒视频观看 | 国产精品酒店视频免费看| 国产a视频精品免费观看| 中文字幕免费视频一| 男人的天堂网免费网站| 两个人看的www视频免费完整版| 老司机免费午夜精品视频| 国产精品久久久久久亚洲影视 | 99热这里有免费国产精品| 97无码人妻福利免费公开在线视频 | 亚洲第一页中文字幕| 久久亚洲中文字幕精品有坂深雪| 亚洲国产精品无码久久久不卡| 亚洲欧洲日产国码无码久久99| 亚洲情综合五月天| 亚洲第一中文字幕| 亚洲美女人黄网成人女| 亚洲成a人片在线网站| 亚洲国产成a人v在线| 亚洲熟妇成人精品一区| 久久久久久亚洲精品无码| 免费又黄又爽又猛大片午夜 | 亚洲AV之男人的天堂| 亚洲а∨天堂久久精品|