JAVA Zero Copy的相關知識

來源:互聯網
上載者:User

標籤:des   style   blog   http   color   java   使用   os   

介紹

     java 的zero copy多在網路應用程式中使用。Java的libaries在linux和unix中支援zero copy,關鍵的api是java.nio.channel.FileChannel的transferTo(),transferFrom()方法。我們可以用這兩個方法來把bytes直接從調用它的channel傳輸到另一個writable byte channel,中間不會使data經過應用程式,以便提高資料轉移的效率。

傳統的資料複製方式及涉及到的環境切換:

      通過網路把一個檔案傳輸給另一個程式,在OS的內部,這個copy操作要經曆四次user mode和kernel mode之間的上下文切換,甚至連資料都被拷貝了四次,如:

    具體步驟如下:

  1. read() 調用導致一次從user mode到kernel mode的環境切換。在內部調用了sys_read() 來從檔案中讀取data。第一次copy由DMA (direct memory access)egine完成,將檔案內容從disk讀出,儲存在kernel的buffer中。
  2. 然後請求的資料被copy到user buffer中,此時read()成功返回。調用的返回觸發了第二次context switch: 從kernel到user。至此,資料存放區在user的buffer中。
  3. send() Socket call 帶來了第三次context switch,這次是從user mode到kernel mode。同時,也發生了第三次copy:把data放到了kernel adress space中。當然,這次的kernel buffer和第一步的buffer是不同的buffer。
  4. 最終 send() system call 返回了,同時也造成了第四次context switch。同時第四次copy發生,DMA egine將data從kernel buffer拷貝到protocol engine中。第四次copy是獨立而且非同步。

        

        


資料轉移(data transfer): zero copy方式及涉及的上下文轉換

        在linux 2.4及以上版本的核心中(如linux 6或centos 6以上的版本),開發人員修改了socket buffer descriptor,使網卡支援 gather operation,通過kernel進一步減少資料的拷貝操作。這個方法不僅減少了context switch,還消除了和CPU有關的資料拷貝。user層面的使用方法沒有變,但是內部原理卻發生了變化:

  1. transferTo()方法使得檔案內容被copy到了kernel buffer,這一動作由DMA engine完成。
  2. 沒有data被copy到socket buffer。取而代之的是socket buffer被追加了一些descriptor的資訊,包括data的位置和長度。然後DMA engine直接把data從kernel buffer傳輸到protocol engine,這樣就消除了唯一的一次需要佔用CPU的拷貝操作。

        

            


代碼範例:

展示通過網路把一個檔案從client傳到server的過程

package zerocopy;import java.io.IOException;import java.net.InetSocketAddress;import java.net.ServerSocket;import java.nio.ByteBuffer;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;public class TransferToServer {ServerSocketChannel listener = null;protected void mySetup() {InetSocketAddress listenAddr = new InetSocketAddress(9026);try {listener = ServerSocketChannel.open();ServerSocket ss = listener.socket();ss.setReuseAddress(true);ss.bind(listenAddr);System.out.println("監聽的連接埠:" + listenAddr.toString());} catch (IOException e) {System.out.println("連接埠綁定失敗 : "+ listenAddr.toString() + " 連接埠可能已經被使用,出錯原因: "+ e.getMessage());e.printStackTrace();}}public static void main(String[] args) {TransferToServer dns = new TransferToServer();dns.mySetup();dns.readData();}private void readData() {ByteBuffer dst = ByteBuffer.allocate(4096);try {while (true) {SocketChannel conn = listener.accept();System.out.println("建立的串連: " + conn);conn.configureBlocking(true);int nread = 0;while (nread != -1) {try {nread = conn.read(dst);} catch (IOException e) {e.printStackTrace();nread = -1;}dst.rewind();}}} catch (IOException e) {e.printStackTrace();}}}
package zerocopy;import java.io.FileInputStream;import java.io.IOException;import java.net.InetSocketAddress;import java.net.SocketAddress;import java.nio.channels.FileChannel;import java.nio.channels.SocketChannel;public class TransferToClient {public static void main(String[] args) throws IOException {TransferToClient sfc = new TransferToClient();sfc.testSendfile();}public void testSendfile() throws IOException {String host = "localhost";int port = 9026;SocketAddress sad = new InetSocketAddress(host, port);SocketChannel sc = SocketChannel.open();sc.connect(sad);sc.configureBlocking(true);String fname = "src/main/java/zerocopy/test.data";FileChannel fc = new FileInputStream(fname).getChannel();long start = System.nanoTime();long nsent = 0, curnset = 0;curnset = fc.transferTo(0, fc.size(), sc);System.out.println("發送的總位元組數:" + curnset+ " 耗時(ns):"+ (System.nanoTime() - start));try {sc.close();fc.close();} catch (IOException e) {System.out.println(e);}}}

其它zero copy的用法 

package zerocopy;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.RandomAccessFile;import java.nio.channels.FileChannel;public class ZerocopyDemo {@SuppressWarnings("resource")public static void transferToDemo(String from, String to) throws IOException {FileChannel fromChannel = new RandomAccessFile(from, "rw").getChannel();FileChannel toChannel = new RandomAccessFile(to, "rw").getChannel();long position = 0;long count = fromChannel.size();fromChannel.transferTo(position, count, toChannel);fromChannel.close();toChannel.close();}@SuppressWarnings("resource")public static void transferFromDemo(String from, String to)throws IOException {FileChannel fromChannel = new FileInputStream(from).getChannel();FileChannel toChannel = new FileOutputStream(to).getChannel();long position = 0;long count = fromChannel.size();toChannel.transferFrom(fromChannel, position, count);fromChannel.close();toChannel.close();}public static void main(String[] args) throws IOException {String from="src/main/java/zerocopy/1.data";String to="src/main/java/zerocopy/2.data";//transferToDemo(from,to);transferFromDemo(from,to);}}
參考

https://www.ibm.com/developerworks/linux/library/j-zerocopy/

http://blog.csdn.net/flyingqr/article/details/6942645

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.