IO模型(阻塞,非阻塞,多路复用)
在了解IO模型前,先了解什么叫IO,IO得操作是怎么样的?
IO既输入输出,指的是一切操作程序或设备与计算机之间发生的数据传输的过程。它分为IO设备和IO接口两个部分。
- IO设备:就是指可以与计算机进行数据传输的硬件。最常见的I/O设备有打印机、硬盘、键盘和鼠标。从严格意义上来讲,它们中有一些只能算是输入设备(比如说键盘和鼠标);有一些只是输出设备(如打印机)。
- IO接口:就是是主机和外设之间的交接界面,通过接口可以实现主机和外设之间的信息交换。
那IO是怎么操作这些进行数据的传输呢?
而用户进程中的一个完整IO分为两个阶段:
- 用户空间与内核空间交互
- 内核空间与设备空间交互
Linux中的五种IO模型有阻塞IO模型、非阻塞IO模型、信号驱动IO模型、IO多路复用模型、异步IO模型。通常有同步(Sync)/异步(Async),阻塞(Block)/非阻塞(Unblock)四种调用方式。
同步与异步
- 所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。也就是必须一件一件事做,等前一件做完了才能做下一件事。(死等结果)
- 所谓异步,就是当一个异步过程调用发出后,调用者不能立刻得到结果,调用者不用等待这件事完成,可以继续做其他的事情。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。(回调通知)
阻塞与非阻塞
- 阻塞调用是指调用结果返回之前,当前线程会被挂起(线程进入非可执行状态,在这个状态下,CPU不会给线程分配时间片,即线程暂停运行)。函数只有在得到结果之后才会返回。
- 非阻塞调用是指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。
总的来说就是:同步与异步是 两个对象之间的关系,而阻塞与非阻塞是一个对象的状态。
阻塞IO模型(blocking I/O)
场景描述
点完餐后,不知道什么时候能做好,只好坐在餐厅里面等,直到做好,然后吃完才离开。但是不知道饭能什么时候做好,只好在餐厅等,而不能去逛街,直到吃完饭才能去逛街,中间等待做饭的时间浪费掉了。这就是典型的阻塞。
优点:
- 能够及时返回数据,无延迟;
- 对内核开发者来说这是省事了; 缺点:
- 对用户来说处于等待就要付出性能的代价了;
非阻塞IO模型(nonblocking I/O)
场景描述
我女友不甘心白白在这等,又想去逛商场,又担心饭好了。所以我们逛一会,回来询问服务员饭好了没有,来来回回好多次,饭都还没吃都快累死了啦。这就是非阻塞。需要不断的询问,是否准备好了。
同步非阻塞就是 “每隔一会儿瞄一眼进度条” 的轮询(polling)方式。所以,非阻塞 IO的特点是用户进程需要不断的主动询问kernel数据好了没有。
优点:能够在等待任务完成的时间里干其他活了(包括提交其他任务,也就是 “后台” 可以有多个任务在同时执行)。
缺点:任务完成的响应延迟增大了,因为每过一段时间才去轮询一次read操作,而任务可能在两次轮询之间的任意时间完成。这会导致整体数据吞吐量的降低。
IO多路复用模型(I/O multiplexing)
场景描述
与第二个方案差不多,餐厅安装了电子屏幕用来显示点餐的状态,这样我和女友逛街一会,回来就不用去询问服务员了,直接看电子屏幕就可以了。这样每个人的餐是否好了,都直接看电子屏幕就可以了,这就是典型的IO多路复用。
I/O多路复用的主要应用场景如下:
- 服务器需要同时处理多个处于监听状态或者多个连接状态的套接字。
- 服务器需要同时处理多种网络协议的套接字。
在IO 多路复用模型中,对于每一个socket,一般都设置成为non-blocking,但是,整个用户的进程其实是一直被block的。只不过进程是被select这个函数block,而不是被socket IO给block。所以IO多路复用是阻塞在select,epoll这样的系统调用之上,而没有阻塞在真正的I/O系统调用上。
然后下面来几个IO操作例子:
阻塞:
int main()
{int sockfd = socket(AF_INET,SOCK_STREAM,0);struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(9999);addr.sin_addr.s_addr = inet_addr("xxx.xxx.xxx.xxx");bind(sockfd,(struct sockaddr *)&addr,sizeof(addr));listen(sockfd,10);int fd[5];for(int i = 0;i < 5;i++){fd[i] = accept(sockfd,NULL,NULL);}printf("accept 5 ok\n");//在进程中与5个客户端进行通信char buf[20];bzero(buf,20);read(fd[0],buf,20);//阻塞等待fd[0]进行读操作,才能继续执行printf("buf is %s\n",buf);bzero(buf,20);read(fd[1],buf,20);printf("buf is %s\n",buf);bzero(buf,20);read(fd[2],buf,20);printf("buf is %s\n",buf);bzero(buf,20);read(fd[3],buf,20);printf("buf is %s\n",buf);bzero(buf,20);read(fd[4],buf,20);printf("buf is %s\n",buf);
}
通过例子可以发现,如果fd[0]没有打印,那么后面将都不会打印。既阻塞等待fd[0]的IO操作之后在进行其他fd里面的操作。
非阻塞:
int main()
{int sockfd = socket(AF_INET,SOCK_STREAM,0);struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(9999);addr.sin_addr.s_addr = inet_addr("xxx.xxx.xxx.xxx");bind(sockfd,(struct sockaddr *)&addr,sizeof(addr));listen(sockfd,10);int fd[5];for(int i = 0;i < 5;i++){fd[i] = accept(sockfd,NULL,NULL);//阻塞非阻塞属性是在文件描述符中设置int flag = fcntl(fd[i],F_GETFL);flag = flag | O_NONBLOCK;//添加非阻塞fcntl(fd[i],F_SETFL,flag);//把修改后的属性设置回fd[i]}sleep(10);while(1){int num = 0;//在进程中与5个客户端进行通信char buf[20];bzero(buf,20);num = read(fd[0],buf,20);//非阻塞 bzero(buf,20);read(fd[1],buf,20);printf("buf is %s\n",buf);bzero(buf,20);read(fd[2],buf,20);printf("buf is %s\n",buf);bzero(buf,20);read(fd[3],buf,20);printf("buf is %s\n",buf);bzero(buf,20);read(fd[4],buf,20);printf("buf is %s\n",buf);}
}
非阻塞的缺点就是太占用系统资源了,需要反复的去查看是否接收到信息。
多路复用IO:
int main()
{int sockfd = socket(AF_INET,SOCK_STREAM,0);struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(9999);addr.sin_addr.s_addr = inet_addr("192.168.3.172");bind(sockfd,(struct sockaddr *)&addr,sizeof(addr));listen(sockfd,10);int fd[5];for(int i = 0;i < 5;i++){fd[i] = accept(sockfd,NULL,NULL);}//IO多路复用,应该同时管理多个fdfd_set readfds;//读表FD_ZERO(&readfds);FD_SET(fd[0],&readfds);//把文件描述符加入进表中FD_SET(fd[1],&readfds);FD_SET(fd[3],&readfds);FD_SET(fd[4],&readfds);while(1){fd_set temp = readfds;int num = 0;num = select(fd[4]+1,&temp,NULL,NULL,NULL);//只管理文件描述符的读操作,只监视文件描述符可读if(num > 0){printf("%d\n",num);//把readfds中只剩下可操作的(别的客户端发送了数据,当前fd可读)的文件描述符for(int i = 0; i < fd[4]+1;i++){if ( FD_ISSET(i,&temp) ){ char buf[20];read(i,buf,20);//别人发送了数据,当前i文件描述符,可读printf("fd is %d,data is %s\n",i,buf);}}}}return 0;
}
多路复用IO既谁开始发信号那么就对那个文件描述符进行操作。
IO模型(阻塞,非阻塞,多路复用)相关推荐
- IO模型之非阻塞IO
1. IO模型非阻塞 IO Linux下,可以通过设置socket使其变为 non-blocking.当对一个non-blocking socket执行读操作时,流程是这个样子: 从图中可以看出,当用 ...
- 五种IO模型:阻塞/非阻塞/复用/信号驱动/异步IO模型
五种IO模型:阻塞/非阻塞/复用/信号驱动/异步IO模型 1. IO基本概念 1.1 IO概念 1.2 IO的两个阶段 1.2.1 IO的两个阶段-例子说明 1.2 IO种类 2. 五种IO模型 2. ...
- I/O: 阻塞非阻塞I/O 同步异步I/O
我们知道,在Linux(UNIX)操作系统中,共有五种IO模型,分别是:阻塞IO模型.非阻塞IO模型.IO复用模型.信号驱动IO模型以及异步IO模型. 同步IO模型 阻塞IO模型 我们钓鱼的时候,有一 ...
- Java网络编程------IO模型的同步/异步/阻塞/非阻塞(1)
IO模型的同步/异步/阻塞/非阻塞 一.同步/异步/阻塞/非阻塞 1.同步和异步 2.阻塞和非阻塞 3.同步.异步和阻塞.非阻塞组合 二.IO 1.I/O 2.阻塞IO和非阻塞IO 3.同步IO和同步 ...
- 异步就是异步,根本就没有 异步非阻塞IO这个说法。阻塞 非阻塞,同步I/O 异步I/O 的区别
先给大家安利一下这个 https://www.ibm.com/developerworks/cn/linux/l-async/ 里面关于 异步非阻塞IO 是错的. 异步就是异步,别扯 异步阻塞 异步非 ...
- 面试必会系列 - 5.1 网络BIO、NIO、epoll,同步/异步模型、阻塞/非阻塞模型,你能分清吗?
本文已收录至 Github(MD-Notes),若博客中图片模糊或打不开,可以来我的 Github 仓库,包含了完整图文:https://github.com/HanquanHq/MD-Notes,涵 ...
- AIO,BIO,NIO:同步阻塞式IO,同步非阻塞IO,异步非阻塞IO
BIO,同步阻塞式IO,简单理解:一个连接一个线程 NIO,同步非阻塞IO,简单理解:一个请求一个线程 AIO,异步非阻塞IO,简单理解:一个有效请求一个线程 IO:阻塞IO BIO:同步阻塞IO.服 ...
- 两段文章清楚弄明白什么是异步IO、同步IO、同步阻塞IO、同步非阻塞IO、异步阻塞IO、异步非阻塞IO
百科解释:异步IO_百度百科 先看2,再看1,会理解的更好! 1. 2.阻塞和非阻塞 # 阻塞和非阻塞关注的是程序在等待调用结果时的状态 # 阻塞调用是指调用结果返回之前,当前线程会被挂起.调用线程只 ...
- java nio io复用_java 非阻塞IO-java NIO-嗨客网
Java的NIO教程 NIO 官方名称叫做 New IO,在 JDK 1.4 中相对于 BIO 的新 IO.但是也有很多人称之为 NON-BLOCKING IO.和 BIO 比较的话,叫做非阻塞 IO ...
- 同步异步阻塞非阻塞杂记
版权声明:本文可能为博主原创文章,若标明出处可随便转载. https://blog.csdn.net/Jailman/article/details/78498458 gevent实现的协程是同步非阻 ...
最新文章
- 搜索算法,一触即达:GitHub上有个规模最大的开源算法库
- 尚硅谷Java视频教程导航(学习路线图)
- JSTL1.1函数标签库(functions)如fn:length
- 鼠标指针放置上面,显示内容_使鼠标指针远离您键入的内容
- 与Min_25筛有关的一些模板
- AWS Lambda将数据保存在DynamoDB中
- ssm架构 开源项目_6个开源架构项目签出
- Docker 集群环境实现的新方式
- MongoDBTool - 测试版【GUI美化完毕】 源代码发布 --MongoDB爱好者,Winform爱好者 请进...
- RGB转换cv::Mat
- Socket通信的安全策略问题
- 大专读者被裁,但他却拒绝了42k的Offer?| 一名爬虫工程师自述
- Android 开发小TIPS
- 在 Linux 平台及 IPv4 环境中构建 IPv6 测试环境
- js 解二元一次方程组(消元法)
- 学生Web开发人员练习:电影评论II
- 手机微信打不开连接到服务器错误代码,微信打不开文件是怎么回事(微信文件错误代码90018)...
- 如何更改CSDN博客皮肤
- Android本地视频播放器开发--搜索本地视频(1)
- 软件测试工程师这个岗位职责是什么?具体都需要干什么?