多路复用

I/O多路复用select/poll/epoll

Deadly 提交于 2020-02-25 19:52:32
前言 早期操作系统通常将进程中可创建的线程数限制在一个较低的阈值,大约几百个。因此, 操作系统会提供一些高效的方法来实现多路IO,例如Unix的select和poll。现代操作系统中,线程数已经得到了极大的提升,如NPTL线程软件包可支持数十万的线程。 I/O多路复用 select select 允许进程指示内核等待多个事件中的任何一个发生,并只在有一个或多个事件发生或指定时间后返回它。 select函数原型 #include <sys/select.h> #include <sys/time.h> int select(int maxfd,fd_set *rdset,fd_set *wrset,fd_set *exset,struct timeval *timeout); 返回值: 监听到有事件发生的文件描述符的个数,超时为0,错误为 -1. 1.当监视的相应的文件描述符集中满足条件时,比如说读文件描述符集中有数据到来时,内核(I/O)根据状态修改文件描述符集,并返回一个大于0的数。 2.当没有满足条件的文件描述符,且设置的timeval监控时间超时时,select函数会返回一个为0的值。 3.当select返回负值时,发生错误。 参数: maxfd: 是需要监视的最大的文件描述符值+1; rdset、wrset、exset: 是传入传出参数,fd_set类型

Java的BIO,NIO和AIO的区别于演进

落爺英雄遲暮 提交于 2020-02-25 07:28:20
作者:公众号: 我是攻城师 前言 Java里面的IO模型种类较多,主要包括BIO,NIO和AIO,每个IO模型都有不一样的地方,那么这些IO模型是如何演变呢,底层的原理又是怎样的呢? 本文我们就来聊聊。 BIO BIO全称是Blocking IO,是JDK1.4之前的传统IO模型,本身是同步阻塞模式,针对网络通信都是一请求一应答的方式,虽然简化了上层的应用开发,但在性能和可靠性方面存在着巨大瓶颈,试想一下如果每个请求都需要新建一个线程来专门处理,那么在高并发的场景下,机器资源很快就会被耗尽,当然,我们可以通过线程池来优化这种情况,但即使是这样,仍然改变不了阻塞IO的根本问题,就是在IO执行的两个阶段都被block了。拿一个read操作来举例子,在linux中,应用程序向linux发起read操作,会经历两个步骤: 第一个阶段linux内核首先会把需要读取的数据加载到操作系统内核的缓冲区中(Linux文件系统是缓存IO,也称标准IO) 第二个阶段应用程序拷贝内核里面的数据到自己的用户空间中 如果是socket操作,类似也会经历两个步骤: 第一个阶段:通常涉及等待网络上的数据分组包到达,然后被复制到内核的缓冲区 第二个阶段:把数据从内核缓冲区,从内核缓冲区拷贝到用户进程的内存空间里面 同步阻塞IO之所以效率低下,就是因为在这两个阶段,用户的线程或者进程都是阻塞的,期间虽然不占cpu资源

I/O多路复用模型之select(一)

淺唱寂寞╮ 提交于 2020-02-23 15:18:45
原理: select函数会等待,直到描述符句柄中有可用资源(可读、可写、异常)时返回,返回值是可用资源(可读/可写/异常等)描述符的个数(>0),0代表超时,-1代表错误。具体到内核大致是:当应用程序调用select() 函数, 内核就会相应调用 poll_wait(), 把当前进程添加到相应设备的等待队列上,然后将该应用程序进程设置为睡眠状态。直到该设备上的数据可以获取,然后调用wake_up()唤醒该应用程序进程。select每次轮训都会遍历所有描述符句柄。 函数接口: int select(int max_fd,fd_set * readfds,fd_set * writefds,fd_set * exceptfds,struct timeval * timeout); max_fd :fd+1 readfds :可读描述符句柄 writefds :可写描述符句柄 exceptfds:异常描述符句柄 timeout :超时时间 select函数的参数将告诉内核: (1)我们所关心的对应描述符句柄 (2)对于每个描述符我们所关心的条件,是否可读,是否可写或是否异常 (3)希望等待多长时间,struct timeval * timeout struct timeval{ long tv_sec; /*秒 */ long tv_usec; /*微秒 */ } timeout ==

文件IO之多路复用-poll

回眸只為那壹抹淺笑 提交于 2020-02-21 06:55:47
1.函数原型 #include <poll.h> int poll(struct pollfd *fds, nfds_t nfds, int timeout) 参数1:多个文件描述符的集合,为一个数组指针 struct pollfd{ int fd; // 文件描述符 short events; // 期望监控的文件描述符事件:PLLIN,PLLOUT,PLLERR short revents; // 事件结果:PLLIN,PLLOUT,PLLERR }; 参数2:被监控的文件描述符的个数 参数3:监控的时间,单位为ms,负数表示-无限监控 返回值:负-出错,正-监控到有效事件,0-监控时间到。 2.用法-应用程序中怎么调用poll a.打开要监控的文件,并保存文件描述符到struct follfd fds[]数组中。并将要监控的文件描述符信息填到 fds[]数组中。 struct follfd fds[2]; // 建立要监控的文件描述符数组 // 初始化数组,将要监控的文件描述符信息填入数组。 fds[0].fd = STDIN //打开的文件描述符 fds[0].event = POLLIN //监听的事件 fds[1].fd = STDERR //打开的文件描述符 fds[1].event = POLLIN //监听的事件 b.调用poll函数 int ret = poll

I/O多路复用

半城伤御伤魂 提交于 2020-02-21 05:44:51
I/O多路复用是这样一种机制:通过一个进程去监视多个文件描述符,一旦其中某个描述符就绪(通常是读就绪或者写就绪),就去通知程序进行相应的读或写操作,如果始终没有描述符就绪,则一直阻塞直到超时。 目前支持I/O多路复用的常见系统调用有select、poll和epoll。注意,这三者本质上还是属于同步I/O。 一、select select函数监视的文件描述符有三类,分别是readset、writeset和exceptset。调用该函数后,函数就处于阻塞状态,直到有描述符就绪(有数据可读、可写、异常),或者超时,这时函数返回后,就可以通过遍历数据结构fd_set来找到已就绪的文件描述符。函数原型如下: //若有就绪描述符则返回其数目,若超时则返回0,若出错则返回-1 int select( int maxfdpl, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timeval *timeout); 在连接的文件描述符数量不大时,select函数性能是可以的,但是一旦描述符数量过大,而实际活跃的描述符数量又极少时,性能就有问题了。所以select函数一般有以下几个缺点: 每次调用select都需要把所有的fd从用户态拷贝到内核态,当fd很多时开销比较大;

java nio多路复用 selector

房东的猫 提交于 2020-02-12 19:36:59
文章目录 多路复用selector 多路复用 unix内核中的select/epoll/poll select poll epoll 代码样例 多路复用selector 多路复用 I/O多路复用,I/O是指网络I/O, 多路指多个TCP连接(即socket或者channel),复用指复用一个或几个线程;简单来说:就是使用一个或者几个线程处理多个TCP连接;最大优势是减少系统开销小,不必创建过多的进程/线程,也不必维护这些进程/线程;多路复用分为三种形式select/epoll/poll,在 Java 中, Selector 这个类是 select/epoll/poll 的外包类 , 在不同的平台上, 底层的实现可能有所不同, 但其基本原理是一样的, 其原理图如下所示: unix内核中的select/epoll/poll select 函数: int select ( int maxfdp1 , fd_set * readset , fd_set * writeset , fd_set * exceptset , const struct timeval * timeout ) 返回值:就绪描述符的数目,超时返回 0 ,出错返回 - 1 maxfdp1:描述符个数 * readset、 * writeset、 * exceptset:读、写和异常条件的描述字 * timeout

IO多路复用

天大地大妈咪最大 提交于 2020-02-12 12:03:13
一.IO多路复用 前面用协程实现IO阻塞自动切换,‘如何去实现事件驱动的情况下IO的自动阻塞的的切换,这个学名叫IO多路复用。 比如socketsew64hmay'y'yver,多个客户端连接,单线程下实现并发效果,这就叫多路复用. 同步io和异步IO,阻塞IO和非阻塞IO的区别? 二.IO模型的前戏准备   1.用户空间与内核空间     操作系统的核心是内核,独立于普通应用程序,可以访问受保护的内存空间也有访问底层硬件的权限     为了保证用户进程不能直接操作内核(kernel),保证内核的安全,操作系统将虚拟空间划分为两部分,一部分为内核空间,一部分为用户空间。     各个进程的使用,称为用户空间。   2.进程切换     为了控制进程的执行,内核必须有能力挂起正在CPU运行的程序,并恢复以前挂起的某个进程。进程切换由操作系统完成,任何进程都是在操作系统内核的支持下运行的,是与内核紧密相关.     把进程的pbc移入相应的队列,选择另一个进程执行,并更新pbc。   3.进程的阻塞     正在执行的进程,由于期待的某些事件未发生,入请求系统资源失败,等待某种操作的完成,新数据尚未到达或无新工作等。则由系统自动执行阻塞,使自己由运行状态变为阻塞状态。进程阻塞是进程自身的一种主动行为,因此只有处于运行状态的进程(获得cpu),才可能将其转换为阻塞状态。当进程进入阻塞状态

JAVA IO/NIO

痴心易碎 提交于 2020-02-10 00:50:55
个人博客 http://www.milovetingting.cn JAVA IO/NIO 前言 本文为学习Java相关知识所作笔记,参考以下资料: https://github.com/Snailclimb/JavaGuide ,感谢原作者的分享! JAVA IO/NIO 阻塞 IO 模型 最传统的一种 IO 模型,即在读写数据过程中会发生阻塞现象。当用户线程发出 IO 请求之后,内核会去查看数据是否就绪,如果没有就绪就会等待数据就绪,而用户线程就会处于阻塞状态,用户线程交出 CPU。当数据就绪之后,内核会将数据拷贝到用户线程,并返回结果给用户线程,用户线程才解除 block 状态。典型的阻塞 IO 模型的例子为:data = socket.read();如果数据没有就绪,就会一直阻塞在 read 方法 非阻塞 IO 模型 当用户线程发起一个 read 操作后,并不需要等待,而是马上就得到了一个结果。如果结果是一个error 时,它就知道数据还没有准备好,于是它可以再次发送 read 操作。一旦内核中的数据准备好了,并且又再次收到了用户线程的请求,那么它马上就将数据拷贝到了用户线程,然后返回。所以事实上,在非阻塞 IO 模型中,用户线程需要不断地询问内核数据是否就绪,也就说非阻塞 IO 不会交出 CPU,而会一直占用 CPU。典型的非阻塞 IO 模型一般如下: while

阻塞I/O、非阻塞I/O和I/O多路复用

£可爱£侵袭症+ 提交于 2020-02-05 13:23:00
一、阻塞I/O 首先,要从你常用的IO操作谈起,比如read和write,通常IO操作都是阻塞I/O的,也就是说当你调用read时,如果没有数据收到,那么线程或者进程就会被挂起,直到收到数据。阻塞的意思,就是一直等着。阻塞I/O就是等着数据过来,进行读写操作。应用的函数进行调用,但是内核一直没有返回,就一直等着。应用的函数长时间处于等待结果的状态,我们就称为阻塞I/O。每个应用都得等着,每个应用都在等着,浪费啊!很像现实中的情况。大家都不干活,等着数据过来,过来工作一下,没有的话继续等着。 二、非阻塞I/O 非阻塞IO很简单,通过fcntl(POSIX)或ioctl(Unix)设为非阻塞模式,这时,当你调用read时,如果有数据收到,就返回数据,如果没有数据收到,就立刻返回一个错误,如EWOULDBLOCK。这样是不会阻塞线程了,但是你还是要不断的轮询来读取或写入。相当于你去查看有没有数据,告诉你没有,过一会再来吧!应用过一会再来问,有没有数据?没有数据,会有一个返回。但是依旧很不好。应用必须得过一会来一下,问问内核有木有数据啊。这和现实很像啊!好多情况都得去某些地方问问好了没有?木有,明天再过来。明天,好了木有?木有,后天再过来。。。。。忙碌的应用。。。。 三、I/O多路复用 多路复用是指使用一个线程来检查多个文件描述符(Socket)的就绪状态

Java NIO的多路复用及reactor

微笑、不失礼 提交于 2020-02-04 00:12:02
(from:http://developer.51cto.com/art/201112/306489.htm) 以下描述,为了说明问题,就提提历史(类似的东西,网上一搜一大把,但是希望你能在这里止步,知道到底是怎么回事。如果还是不清楚,咱就站内沟通!)。 在我(刚)看nio的这段时间里,主要接触了几个东西,就是关于server和client。java之前的io完全可以胜任,但是效率不高,为何效率不高呢? ===============history==start=============== //TODO:finish the old style of server and socket data transion. ServerSocket socket = new ServerSocket(80); while (true) { final Socket connection = socket.accept(); handleRequest(connection); } ===============history==end in the future================ 在上面的代码片段中,我们只能是一个request一个的进行处理。这使得所有的请求都阻塞了。如果我们再改变一下,将handleRequest方法封装到线程中处理: if(connection =