java-NIO操作

1、NIO非阻塞

NIO(Non-blocking I/O),是一种同步非阻塞的I/O模型,也是I/O多路复用的基础,已经被越来越多地应用到大型应用服务器,称为处理解决高并发与大量连接、I/O处理的有效方式。

与NIO对比,以前使用最多的是BIO(blocking IO),也就是阻塞式IO,这种io模式在活动连接数不是特别高的时候(小于1000),还是非常不错的,当io阻塞系统时可以利用多线程,最大限度地使用CPU资源。

Linux提供的零拷贝技术Java并不是全部支持,目前只支持两种(内存映射mmap/sendfile),NIO提供的sendfile, FileChannel.transferTo()方法直接将当前通道内容传输到另外一个通道,没有涉及到Buffer的任何操作,NIO中的Buffer是JVM堆或者堆外内存,但不论如何他们都是操作系统内核空间的内存。transferTo()的实现方式就是通过系统调用sendfile()(是通过Linux中的系统调用)。值得注意的是Java NIO提供的FileChannel.transferTo 和 transferFrom 并不保证一定能使用零copy。实际上是否能使用零拷贝与操作系统有关,如果操作系统提供sendfile 这样的零拷贝系统函数,那么这两个方法就会借助这样的系统调用充分利用零拷贝的优势,否则并不能通过这两个方法本身实现零拷贝的。

2、Linux支持的常见零拷贝

DMA(Direct Memory Access,直接内存存取)是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依赖于CPU的大量中断负载。

(1)mmap内存映射

DMA加载磁盘数据到kernel buffer之后,应用程序缓冲区(application buffers)和内核缓冲区(kernel buffer)进行映射,数据在应用缓冲区和内核缓冲区的改变就能省略

mmap 内存映射将会经历3次copy,1次cpu拷贝,2次DMA copy以及4次上下文切换

(2)sendfile

        linux 2.1 支持的sendfile.当调用sendfile()时,DMA将磁盘数据复制到kernel buffer, 然后将内核中的kernel buffer 直接拷贝到socket buffer;一旦数据全部拷贝到socket buffer,

sendfile()系统调用将会return,代表数据的转化的完成。socket buffer 里的数据剧可以在网络里面进行网络传输了

sendfile 会经历:3次拷贝,1次cpu拷贝 2次DMA 拷贝,以及2次上下文切换。

我们用传统的IO以及NIO 零copy分别复制不同代销的文件,零拷贝随着文件的增大省出的时间还是非常可观的。

/**
 * @Author: chenxiangweifeng
 * @Date: 2020/12/20 16:40
 * java nio java non-balocking java非阻塞式IO操作
 */
public class NioDemo {
    @Test
    public void zeroCopy() throws Exception{
        long start = System.currentTimeMillis();
        File src = new File("D://Linux-iso/ubuntu-16.04.3-desktop-amd64.iso");
        File dst = new File("D://dst-zero.iso");

        FileChannel in = FileChannel.open(src.toPath(), StandardOpenOption.READ);
        FileChannel out = FileChannel.open(dst.toPath(), StandardOpenOption.CREATE, StandardOpenOption.WRITE);
        in.transferTo(0,in.size(),out);
        long end = System.currentTimeMillis();
        System.out.println("复制耗时毫秒数:"+(end-start));
        in.close();
        out.close();
    }

    @Test
    public void directCopy() throws Exception{
        long start = System.currentTimeMillis();
        File src = new File("D://Linux-iso/ubuntu-16.04.3-desktop-amd64.iso");
        File dst = new File("D://dst.iso");
        BufferedInputStream in = new BufferedInputStream(new FileInputStream(src));
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dst));
        byte[] buffer = new byte[1024];
        int len = 0;
        int count = 0;
        while ((len = in.read(buffer)) != -1 ){
            count++;
            out.write(buffer);
        }
        long end = System.currentTimeMillis();
        System.out.println("循环次数:"+count);
        System.out.println("复制耗时毫秒数:"+(end-start));
        in.close();
        out.close();
    }

结果我们复制一个112mb的文件

文件大小传统IO  (ms)零copy  (ms)
112MB1198773
1GB3708010957

可以看出、使用零copy技术在文件传输大文件上速度还是非常快!

参考文档:Java中的零拷贝  https://www.jianshu.com/p/2fd2f03b4cc3

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值