网站导航栏制作教程,企业网站建设流程介绍,辽宁省建筑工程造价信息网,设计网站的步骤有哪些IO分类
阻塞和非阻塞
阻塞IO#xff1a;用户空间引发内核空间的系统调用#xff0c;需要内核IO操作彻底完成之后#xff0c;返回值才会返回到用户空间#xff0c;执行用户的操作。阻塞指的用户空间程序的执行状态#xff0c;用户空间程序需要等到IO操作彻底执行完毕。j…IO分类
阻塞和非阻塞
阻塞IO用户空间引发内核空间的系统调用需要内核IO操作彻底完成之后返回值才会返回到用户空间执行用户的操作。阻塞指的用户空间程序的执行状态用户空间程序需要等到IO操作彻底执行完毕。java中默认创建的socket是阻塞的。
非阻塞IO用户空间引发内核空间的系统调用不需要等待内核IO操作彻底完成内核立即给用户返回一个返回值。用户空间程序继续执行用户的操作处于非阻塞的状态。java中设置非阻塞的IO以socket为例见如下所示的代码
serverChannel ServerSocketChannel.open()
serverChannel.configureBlocking(false)有兴趣也可以参考java中关于Socket这个类的文档
同步和异步
同步IO用户空间和内核空间的调用发起方式。同步IO是指用户空间的线程是主动发起IO请求的一方内核空间是被动接受方。
异步IO用户空间和内核空间的调用发起方式。异步IO是指用户空间的线程是被动接受方但是内核空间里面的kernel是主动发起IO请求的一方。
四种常见的IO模型
服务器端的编程需要构造高性能的IO模型常见的IO模型有四类 同步阻塞IOBlocking IO
结合上面的描述同步阻塞IO指的是用户空间主动发起的调用然后需要等待内核空间将IO操作彻底完成之后才会返回用户空间这期间用户空间线程将会处于阻塞状态。
BIO优点 程序简单在阻塞等待数据的期间用户挂起线程用户线程基本不会占用CPU资源。
BIO缺点每个请求可能会配置一套独立的线程当并发量很高的场景下内存和线程切换的成本很高。
应用举例在Java中使用线程池的方式去连接数据库就是使用的同步阻塞IO模型。
同步非阻塞IONon-blocking IO
如果是socket被设置为non-blockingNIO模型如果出现了系统调用会出现以下两种情况
1当内核缓存区里面没有数据那么当用户空间发起的系统调用时会立即返回一个失败的信息
2当内核缓存区里面有数据那么当用户空间发起的系统调用时会进入到阻塞状态将内核缓存区里面的数据复制到用户缓冲区。直到数据返回成功才会解除阻塞的状态。 NIO的优点每次发起IO系统调用线程在内核等待缓冲区数据的时候会立即返回值不会阻塞。实时性比较好。
NIO的缺点需要不断地轮询发起系统调用这样会占用大量的CPU时间资源利用率很低。
IO多路复用IO Multiplexing
首先从字面意思来理解多路复用 多路 多个socket网络连接 复用复用一个线程使用一个线程来检查多个文件套接字又称文件句柄的就绪状态
IO多路复用是一种同步IO模型实现用一个线程监视多个文件句柄一旦有文件句柄准备就绪就可以通知应用程序进行相应的读写操作。没有文件句柄就绪就会阻塞应用程序然后交出CPU的时间片。
通过对之前两种IO模型的总结我们可以发现 针对高并发的场景同步阻塞模型的缺点是需要做频繁的内存和线程的切换效率很低。同步非阻塞的缺点是要在用户程序空间轮询的发起系统调用这导致内核态和用户态的频繁切换也会消耗大量的资源。 IO多路复用则可以避免内核态和用户态的频繁切换因为IO多路复用模型将轮询套接字又称为文件句柄的动作直接放在了内核态进行这样避免了内核态和用户态的频繁切换
举例说明
我们以基础的socket模型为例展现IO多路复用的机制
下面是基础的socket模型伪码
listenSocket socket(); //系统调用socket()函数调用创建一个主动socket
bind(listenSocket); //给主动socket绑定地址和端口
listen(listenSocket); //将默认的主动socket转换成服务器使用的被动socket(也叫监听socket)
while(true) { //循环监听客户端的连接请求connectSocket accept(listenSocket); //接受客户端连接获取已连接socketrecv(connSocket); //从客户端读取数据只能同时处理一个客户端send(connSocket); //给客户端返回数据只能同时处理一个客户端
}网络通信的流程如下图所示
上图所示的socket网络通信是典型的同步阻塞模型当有大量客户端连接时这种模型的处理性能比较差。使用IO多路复用可以解决这种困境。 linux中操作系统提供了select、poll和epoll三种多路复用机制。
select机制 四个问题 1、IO多路复用可以最多监听多少个socket 2、IO多路复用可以监听socket里面的哪些事件 3、IO多路复用如何感知已经就绪的文件描述符fd 4、IO多路复用如何实现网络通信 首先在linux平台上查看一下select函数定义,可以参考一下文章1Linux内核select源码剖析 、文章2Linux select源码分析。
/**
* 参数说明
* 监听的文件描述符数量 __nfds
* 被监听描述符的三个集合*__readfds, *__writefds 和 *__exceptfds
* 监听时阻塞等待的超时时长*__timeout
* 返回值返回一个socket对应的文件描述符
*/
int select(int __nfds, fd_set * __readfds, fd_set * __writefds, fd_set * __exceptfds, struct timeval * __timeout)select函数监听的文件描述符被分成三类分别是__readfds, __writefds 和 __exceptfds当用户调用select时假设当前监控的是___readfds集合select操作会将需要监控___readfds集合从用户空间拷贝到内核空间随后在内核空间一直遍历自身的skb(SocketBuffer)检查每个skb的poll逻辑已确定socket是否存在可读事件。若没有socket可读则会进入到睡眠状态。当发现有sokcet可读则会唤醒用户空间的程序然后在用户态去遍历监控的集合并读取数据。 select 多路复用方法存在的缺陷
1、调用select需要将套接字列表从用户态复制到内核态对于多并发场景资源消耗量比较大。
2、能监听的端口号的数量有限制FD_SETSIZE,32位机器限制1024个套接字64位机器限制2048个套接字。
3、被监控的fdlist列表如果有一个套接字数据可读业务就需要遍历一遍用户态的fdlist列表时间复杂度O(n)。
poll
相较于selectpoll优化了select的缺陷二使用的是动态数组结构而不是select的bitMap结构突破了1024的限制但是poll也没有解决缺陷1和缺陷3仍然存在用户态到内核态的套接字复制而导致的资源消耗过大的问题。