前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >再谈NIO

再谈NIO

作者头像
搬砖俱乐部
发布2020-01-17 15:42:29
4240
发布2020-01-17 15:42:29
举报
文章被收录于专栏:BanzClubBanzClub

对于操作系统来说,如果要操作某个文件,通常是通过进程或者线程来先打开目标文件,再进行读写操作;

文件描述符

操作系统的底层实现是,先要“描述”,再“操作”,这个“描述”其实就是在操作系统内核中,为该文件存一个标识,这个标识就对应这个文件,就相当于对文件进行了一个抽象,存在了内核区文件描述符表,这个对文件的抽象就是文件描述符;

系统默认情况下会帮我们打开三个文件描述符,0代表是标准输入、1代表是标准输出、2代表标准Error。

每个程序可以打开的文件描述符是有上线的,每个操作系统不一致,我们可以通过 ulimit -a 命令查看默认的系统限制是多少;

系统默认情况下是有最高上限的,可以通过查看 /proc/sys/fs/file-max 文件得到上限值;

在C程序中,文件由文件指针或者文件描述符表示。ISO C的标准I/0库函数(fopen, fclose, fread, fwrite, fscanf, fprintf等)使用文件指针,UNIX的I/O函数(open, close, read, write, ioctl)使用文件描述符。

当拿到一个文件描述符都可以进行read或者write,但是具体的read和write却跟对应文件描述符的具体实现不同。比如socket的就是走网络,普通文件的就是走磁盘IO。

为了将不同的类型的I/O与对应的文件描述符绑定,则是需要不同的初始化函数的。普通文件就通过open函数,指定对应的文件路径,操作系统通过路径能够找到对应的文件系统类型,如ext4,fat等等。如果是网络呢,就通过socket函数来初始化,socket函数就通过(domain, type, protocol)来找到对应的网络协议栈,比如TCP/IP,UNIX等等。

缓冲区

  • 缓冲区
    • 容量(capacity)
    • 限制(limit):用于表示limit后面的空间不可用,一般读数据时,待读的数据不会总是充满整个缓冲区的,用limit表示,limit之前的空间可读,后面空间不可用;
    • 位置(position):下一个要读取或写入数据的索引位置
    • 标记(mark)与重置(reset):用于标记传输到哪个位置,可用来保证数据传输的完整性;也可实现重复读;
  • 用途
    • 存入数据到缓冲区
    • 获取缓冲区数据
  • 类型
    • 直接缓冲区
  • 非直接缓冲区

操作系统在处理I/O时,为了最大限度的利用CPU,避免CPU由于等待I/O而白白的浪费掉运行周期,而将CPU从I/O工作中解放出来,DMA和通道都是为了解决这个问题的。不过CPU不可能完全被释放出来。 1、阻塞式

2、DMA

3、通道

  • 种类:
    • FileChannel
    • SocketChannel
    • ServerSocketChannel
    • DatagramChannel
    • 管道
      • Pipe.SinkChannel
      • Pipe.SourceChannel

阻塞与非阻塞

传统IO是阻塞式的,当一个线程调用read和write时,该线程被阻塞,直到有一些数据被读取或者写入,该线程在此期间不能执行其他任务,也就是在完成IO操作时,线程会被阻塞,所以服务器会为每一个客户端请求都提供一个独立的线程进行处理,当服务端有大量来自客户端的请求时,由于创建大量线程等原因,将导致性能急剧下降;

而非阻塞式的IO,读写数据是通过线程的通道进行的,若读写数据没有准备好,线程是可以进行其他任务的,通常线程的空闲时间,用于在其他通道上进行IO操作,这样单个线程可以处理很多来自客户端的IO请求,这大大减轻了服务端的压力;

选择器:是多路复用器,可以同时监控多个Channel的IO状况,通过Selector可以使单线程管理多个Channel,属于非阻塞IO的核心;

  • 种类:
    • select:线性扫描所有监听的文件描述符,不管他们是不是活跃的。有最大数量限制(32位系统1024,64位系统2048)
    • poll:同select,不过数据结构不同,需要分配一个pollfd结构数组,维护在内核中。它没有大小限制,不过需要很多复制操作
    • epoll:用于代替poll和select,没有大小限制。使用一个文件描述符管理多个文件描述符,使用红黑树存储。同时用事件驱动代替了轮询。epoll_ctl中注册的文件描述符在事件触发的时候会通过回调机制激活该文件描述符。epoll_wait便会收到通知。最后,epoll还采用了mmap虚拟内存映射技术减少用户态和内核态数据传输的开销

线程模型

  • 轮询:不断使用线程轮询
  • 事件驱动
    • Reactor模式(反应器):上面所说的Selector、Channel其实就是一个简单的Reactor模式
      • Reactor:负责响应IO事件,当检测到一个新的事件,将其发送给相应的Handler去处理
      • Handler:将自身(handler)与事件绑定,负责事件的处理,完成channel的读入,完成处理业务逻辑后,负责将结果写出channel

引申阅读

  • 零拷贝
  • C10K问题
  • NIO空轮询问题

1、https://blog.51cto.com/keren/170822

2、https://blog.csdn.net/u011555996/article/details/51208887

3、https://mp.weixin.qq.com/s/UWdZsvPsV46VLpr7qHjgjA

4、https://www.cnblogs.com/imstudy/p/9908791.html

5、https://www.jianshu.com/p/188ef8462100

6、https://www.cnblogs.com/crazymakercircle/p/9833847.html

7、https://www.cnblogs.com/crazymakercircle/p/10225159.html

8、http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-01-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 BanzClub 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档