传统文件io 从磁盘读取一个文件 到通过网络传输出去 经过4次IO复制 3次上下文切换
对其进行优化
经过mmap优化,4次复制 变为3次 上下文切换不变
由4次复制减少到3次复制 内核切换由4次减少到3次
继续优化 由4次复制减少到2次,内核切换由4次减少到3次
一个基本的案例:
BIO拷贝一个文件的时间
import java.io.DataInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
*
*/
public class OldIOServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket=new ServerSocket(7001);
while (true){
Socket socket= serverSocket.accept();
DataInputStream dataInputStream=new DataInputStream(socket.getInputStream());
try {
byte[] bytes=new byte[4096];
while (true){
int read = dataInputStream.read(bytes, 0, bytes.length);
if(read==-1){
break;
}
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
/**
*
*/
public class OldIOClient {
public static void main(String[] args) throws IOException {
Socket socket=new Socket("127.0.0.1",7001);
InputStream inputStream=new FileInputStream("aa.txt");
DataOutputStream dataOutputStream=new DataOutputStream(socket.getOutputStream());
byte[] buffer=new byte[4096];
long count=0;
long readCount=0;
long startTime=System.currentTimeMillis();
while ((readCount=inputStream.read(buffer))>0){
count+=readCount;
dataOutputStream.write(buffer);
}
System.out.println("总共发送了字节数:"+count+"耗时:"+(System.currentTimeMillis()-startTime)/1000);
dataOutputStream.close();
socket.close();
inputStream.close();
}
}
BIO的拷贝一个大文件的时间
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
/**
*零拷贝是 没有cpu拷贝
* * mmap 4次拷贝--3次 3次切换--3次切换
* * sendFile 4次拷贝--3次 3次切换--2次切换
* * DMA拷贝 直接内存 从磁盘到内存 使用DMA拷贝 内存到磁盘也是DMA linux内存到虚拟机 需要cpu拷贝,虚拟机到内存 需要cpu拷贝 所以是4次拷贝
* *
*/
public class NewZeroCopyServer {
public static void main(String[] args) throws IOException {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(7001));
ByteBuffer byteBuffer = ByteBuffer.allocate(4096);
while (true){
SocketChannel socketChannel = serverSocketChannel.accept();
int readCount=0;
while (readCount!=-1){
try {
readCount=socketChannel.read(byteBuffer);
}catch (Exception e){
e.printStackTrace();
}
byteBuffer.rewind();
}
}
}
}
import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
/**
*
*/
public class NewZeroCopyClient {
public static void main(String[] args) throws IOException {
SocketChannel socketChannel = SocketChannel.open();
socketChannel.bind(new InetSocketAddress("127.0.0.1",7001));
//文件输入流
FileChannel fileChannel=new FileInputStream("aa.txt").getChannel();
long startTime=System.currentTimeMillis();
//linux 下 tranferTo 可以将数据拷贝
//windows下tranferTo 只能拷贝8M的数据,因此需要分段传输
//transferTo 底层使用了0拷贝
long transferCount = fileChannel.transferTo(0, fileChannel.size(), socketChannel);
System.out.println("发送总的字节数="+transferCount+"耗时:"+(System.currentTimeMillis()-startTime)/1000);
fileChannel.close();
socketChannel.close();
}
}