摘要:什么是零拷貝我們首先來認(rèn)識一下傳統(tǒng)的操作。因?yàn)樵谶@套體系里,不僅僅提供了非阻塞的編程模型,而且提供了類似零拷貝,內(nèi)存映射這樣的新技術(shù)對于操作系統(tǒng)來說早就有了。
什么是零拷貝?
我們首先來認(rèn)識一下傳統(tǒng)的I/O操作。
假如說用戶進(jìn)程現(xiàn)在要把一個文件復(fù)制到另一個地方。
那么用戶程序必須先把這個文件讀入內(nèi)存,然后再把內(nèi)存里的數(shù)據(jù)寫入另一個文件。
不過文件讀入內(nèi)存也不是直接讀入用戶進(jìn)程的內(nèi)存,而是先讀入操作系統(tǒng)內(nèi)核的內(nèi)存,然后再從操作系統(tǒng)內(nèi)核的內(nèi)存區(qū)讀到用戶進(jìn)程的內(nèi)存。
與之對應(yīng)的是,寫文件也不是直接寫到磁盤上的文件,而是用戶進(jìn)程先把自己內(nèi)存的數(shù)據(jù)傳到操作系統(tǒng)內(nèi)核的內(nèi)存,然后再從操作系統(tǒng)內(nèi)核的內(nèi)存區(qū)寫到磁盤。而這其中涉及到諸多的系統(tǒng)調(diào)用。
因此看上去簡單的操作至少要分為四部
1磁盤文件讀入操作系統(tǒng)
2操作系統(tǒng)讀到用戶進(jìn)程
3用戶進(jìn)程寫到操作系統(tǒng)
4操作系統(tǒng)寫入磁盤文件
零拷貝和傳統(tǒng)I/O有和不同?
零拷貝就是指,傳輸一個文件的時候,不需要把文件讀到用戶進(jìn)程再處理,而是直接把文件讀到操作系統(tǒng)一個內(nèi)存區(qū),然后再移動到操作系統(tǒng)的另一個內(nèi)存區(qū),最后寫入文件。
這樣一來,步驟變成這樣:
1磁盤文件讀入操作系統(tǒng)
2操作系統(tǒng)把數(shù)據(jù)寫入操作系統(tǒng)另一個區(qū)域
3操作系統(tǒng)寫入磁盤文件
雖然只少了一步,但是這里不僅減少了數(shù)據(jù)移動的時間損耗,而且減少了系統(tǒng)調(diào)用的次數(shù),因此大大縮短了時間。
更加詳細(xì)的解釋請看https://blog.csdn.net/u010530...
java里如何實(shí)現(xiàn)零拷貝呢?
這就要說起java nio中的FileChannel.transferTo()方法了,該方法是把FileChannel中的數(shù)據(jù)利用零靠的技術(shù)轉(zhuǎn)移到另一個channel。這另一個channel往往是FileChannel,不過SocketChannel也是可以的:)。
簡單實(shí)現(xiàn)(靜態(tài)下載文件,不能根據(jù)用戶指令來更改下載的文件。)
代碼如下:
單線程版本:
package qiuqi.filedownloadtest; import java.io.FileInputStream; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.channels.*; import java.util.Iterator; public class FileServer { public static void main(String[] args) throws IOException { startServer(); } public static void startServer() throws IOException { ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.bind(new InetSocketAddress(9999)); serverSocketChannel.configureBlocking(false); Selector selector = Selector.open(); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); while (selector.select() > 0) { Iteratoriterator = selector.selectedKeys().iterator(); while (iterator.hasNext()) { SelectionKey key = iterator.next(); iterator.remove(); if(key.isAcceptable()) { SocketChannel socketChannel = serverSocketChannel.accept(); try (FileInputStream in = new FileInputStream("C:UsersdellDesktopOL手機(jī)數(shù)據(jù)(1).rar")){ long size = in.available(); long num = 0; long begin = 0; while ( (num = in.getChannel().transferTo(begin,size,socketChannel))!=0) { size-=num; begin += num; } socketChannel.close(); } catch (IOException e){e.printStackTrace();} } } } } }
多線程版本:
package qiuqi.filedownloadtest; import java.io.FileInputStream; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.channels.*; import java.util.Iterator; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class FileServer { static ExecutorService threadpool = Executors.newCachedThreadPool(); public static void main(String[] args) throws IOException { startServer(); } public static void startServer() throws IOException { ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.bind(new InetSocketAddress(9999)); serverSocketChannel.configureBlocking(false); Selector selector = Selector.open(); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); while (selector.select() > 0) { Iteratoriterator = selector.selectedKeys().iterator(); while (iterator.hasNext()) { SelectionKey key = iterator.next(); iterator.remove(); if(key.isAcceptable()) { SocketChannel socketChannel = serverSocketChannel.accept(); threadpool.execute(new Runnable() { @Override public void run() { try (FileInputStream in = new FileInputStream("C:UsersdellDesktopOL手機(jī)數(shù)據(jù)(1).rar")){ long size = in.available(); long num = 0; long begin = 0; while ( (num = in.getChannel().transferTo(begin,size,socketChannel))!=0) { size-=num; begin += num; } socketChannel.close(); } catch (IOException e){e.printStackTrace();} } }); } } } } }
代碼就不講解了。如果學(xué)過java nio,那么理解上面的程序輕而易舉。
如果不熟悉java nio的服務(wù)器編程那么請先學(xué)習(xí)再來觀看。
最后我想說,java NIO真的是NEW IO即新的IO,而不是NonBlocking IO即非阻塞IO。因?yàn)樵谶@套體系里,不僅僅提供了非阻塞的編程模型,而且提供了類似零拷貝,內(nèi)存映射這樣的新技術(shù)(對于操作系統(tǒng)來說早就有了)。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/73543.html
摘要:如果什么事都沒得做,它也不會死循環(huán),它會將線程休眠起來,直到下一個事件來了再繼續(xù)干活,這樣的一個線程稱之為線程。而請求處理邏輯既可以使用單獨(dú)的線程池進(jìn)行處理,也可以跟放在讀寫線程一塊處理。 Netty到底是什么 從HTTP說起 有了Netty,你可以實(shí)現(xiàn)自己的HTTP服務(wù)器,F(xiàn)TP服務(wù)器,UDP服務(wù)器,RPC服務(wù)器,WebSocket服務(wù)器,Redis的Proxy服務(wù)器,MySQL的P...
摘要:而每個文件系統(tǒng)又可以設(shè)置不同的調(diào)度算法,另外,還有虛擬內(nèi)存缺頁中斷帶來的性能毛刺良心的提供了調(diào)優(yōu)的腳本,這點(diǎn)做的不錯跑題了。測試環(huán)境核線程內(nèi)存磁盤讀寫左右虛擬內(nèi)存未關(guān)閉,大小測試注意點(diǎn)為了防止緩存的影響,每次都生成一個新的文件進(jìn)行讀取。 前言 Java 在 JDK 1.4 引入了 ByteBuffer 等 NIO 相關(guān)的類,使得 Java 程序員可以拋棄基于 Stream ,從而使用基...
摘要:豐富的緩存數(shù)據(jù)結(jié)構(gòu)使用它自己的緩存來表示字節(jié)序列而不是的。針對有一個定義良好的事件模型。有一些協(xié)議是多層的建立在其他低級協(xié)議基礎(chǔ)上。此外,甚至不是完全線程安全的。協(xié)議由標(biāo)準(zhǔn)化為。協(xié)議緩存整合是一個高效二進(jìn)制協(xié)議的快速實(shí)現(xiàn)。 Chapter 2、結(jié)構(gòu)概覽 這一節(jié)我們將確認(rèn)Netty提供的核心功能是什么,以及它們怎么構(gòu)成一個完整的網(wǎng)絡(luò)應(yīng)用開發(fā)堆棧。 1、豐富的緩存數(shù)據(jù)結(jié)構(gòu) Netty使用它...
摘要:前言從字面意思理解就是數(shù)據(jù)不需要來回的拷貝,大大提升了系統(tǒng)的性能這個詞我們也經(jīng)常在,,,等框架中聽到,經(jīng)常作為其提升性能的一大亮點(diǎn)下面從的幾個概念開始,進(jìn)而在分析零拷貝。 前言 從字面意思理解就是數(shù)據(jù)不需要來回的拷貝,大大提升了系統(tǒng)的性能;這個詞我們也經(jīng)常在java nio,netty,kafka,RocketMQ等框架中聽到,經(jīng)常作為其提升性能的一大亮點(diǎn);下面從I/O的幾個概念開始,...
閱讀 2014·2021-09-22 16:05
閱讀 9336·2021-09-22 15:03
閱讀 2894·2019-08-30 15:53
閱讀 1707·2019-08-29 11:15
閱讀 917·2019-08-26 13:52
閱讀 2361·2019-08-26 11:32
閱讀 1811·2019-08-26 10:38
閱讀 2576·2019-08-23 17:19