题外话
傍晚,下班了,走出公司,迎面而来的幻影停在了我的面前,车门打开,缓缓走下一位风姿绰约的美女,红唇微张说到,少爷,我来接您了,哎,又是乏味的一天…… 生活就是这么平淡 话说最近各地都开始下雪了,都降温了,是真冷啊
跑题了……废话不多说,上货
IO
Select,poll,epoll 是IO多路复用比较常见的机制。 IO是指linux系统中,万物都是文件,所用程序都会被编译成二进制文件,文件的数据从外部读取到内存就是I(Input)反之则是O(Output) 内存与外部设备之间copy数据就是Input and Output,简称I/O,
IO操作依赖于以下几个接口完成对文件的操作 1.open,打开文件 2.seek,改变读写位置 3.read,write,读写文件 4.close,关闭文件
Linux通过文件描述符来获取文件需要执行的操作,当连接多个客户端时,需要对大量的文件执行处理,这时候就需要IO多路复用。
文件描述符(fd)就是提交给系统,告诉系统我这个文件需要什么服务,例如读取,抛出异常等(类似点餐,告诉餐厅我需要吃什么) IO多路复用的流程就是通过调用函数,将所有文件的文件描述符获取,查找需要io操作的文件描述符,对对应的文件进行io操作
Select
1 Select工作机制: select会调用copy_from_user方法将fd_set(一个储存文件描述符的数组)从用户空间拷贝到内核空间(系统内核) 然后遍历fd_set找到需要进行io操作的相关文件描述符,调用方法将对应的文件扔入就绪队列,其他扔入等待队列(阻塞) 2 Select机制缺点: (1)每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大 (2)同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大 (3)select支持的文件描述符数量太小了,默认是1024
poll
2.1 poll工作机制: poll的工作机制大致与select相同,区别点在于对文件描述符描述的不同以及解除了文件描述符数量的限制, poll使用pollfd指定需要监控的文件描述符,不需要显式地请求异常情况报告 2.2 poll机制缺点:虽然解除了文件描述符数量的限制,但频繁在内核与用户拷贝fd仍然会消耗大量的性能
epoll
epoll工作机制 epoll使用epoll_create是创建一个epoll句柄;epoll_ctl是注册要监听的事件类型;epoll_wait则是等待事件的产生来完成工作 epoll的底层是链表加红黑树的数据结构,epoll也会将fd拷贝到内存中,但仅拷贝一次,遍历fd时只是将就绪的fd加入到就绪链表中 每次再次被唤醒,只会查看链表中是否仍然存在就绪fd,链表为空才会再次拷贝fd(就绪链表不是就绪队列,是epoll自己维护的一个) 执行epoll_create()时,创建了红黑树和就绪链表; 执行epoll_ctl()时,如果增加socket句柄,则检查在红黑树中是否存在,存在立即返回,不存在则添加到树干上, 然后向内核注册回调函数,用于当中断事件来临时向准备就绪链表中插入数据; 执行epoll_wait()时立刻返回准备就绪链表里的数据即可,返回数据填入就绪队列。
epoll触发模式
1.水平触发(LT) LT(水平触发)模式下,只要这个文件描述符还有数据可读,每次 epoll_wait都会返回它的事件,提醒用户程序去操作; 通俗讲就是当数据被拷贝进内核中,触发epoll对文件进行操作,但操作可能只读取了一半文件就中断了,这时epoll就会查看 数据缓存区是否仍有数据,如果有就触发第二次epoll,直到数据缓存区内没有任何数据 2.边缘触发(ET) ET(边缘触发)模式下,在它检测到有 I/O 事件时,通过 epoll_wait 调用会得到有事件通知的文件描述符, 对于每一个被通知的文件描述符,如可读,则必须将该文件描述符一直读到空,让 errno 返回 EAGAIN 为止, 否则下次的 epoll_wait 不会返回余下的数据,会丢掉事件。如果ET模式不是非阻塞的,那这个一直读或一直写势必会在最后一次阻塞。 与水平触发的区别在于检查数据缓存区时,有数据也不触发,除非文件描述符再次对该文件进行了描述。
你以为结束了
阻塞类型: 1.同步阻塞I/O: 用户进程进行I/O操作,一直阻塞到I/O操作完成为止。 2. 同步非阻塞I/O: 用户程序可以通过设置文件描述符的属性O_NONBLOCK,I/O操作可以立即返回,但是并不保证I/O操作成功。 3. 异步事件阻塞I/O: 用户进程可以对I/O事件进行阻塞,但是I/O操作并不阻塞。通过select/poll/epoll等函数调用来达到此目的。 4. 异步时间非阻塞I/O: 也叫做异步I/O(AIO),用户程序可以通过向内核发出I/O请求命令,不用等带I/O事件真正发生, 可以继续做另外的事情,等I/O操作完成,内核会通过函数回调或者信号机制通知用户进程。这样很大程度提高了系统吞吐量。 大家看完发现有什么错误,写在下面吧!跟我黑虎阿福比划比划!
|