多路复用

阻塞IO、非阻塞IO、IO多路复用、同步IO、异步IO 的理论

匿名 (未验证) 提交于 2019-12-03 00:41:02
同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?这个问题其实不同的人给出的答案都可能不同,比如wiki,就认为asynchronous IO和non-blocking IO是一个东西。这其实是因为不同的人的知识背景不同,并且在讨论这个问题的时候上下文(context)也不相同。所以,为了更好的回答这个问题,我先限定一下本文的上下文。 本文讨论的背景是Linux环境下的network IO。 Stevens在文章中一共比较了五种IO Model: 由于signal driven IO在实际中并不常用,所以我这只提及剩下的四种IO Model。 再说一下IO发生时涉及的对象和步骤。 对于一个network IO (这里我们以read举例),它会涉及到两个系统对象,一个是调用这个IO的process (or thread),另一个就是系统内核(kernel)。当一个read操作发生时,它会经历两个阶段: 记住这两点很重要,因为这些IO Model的区别就是在两个阶段上各有不同的情况。 在linux中,默认情况下所有的socket都是blocking,一个典型的读操作流程大概是这样: 当用户进程调用了recvfrom这个系统调用

I/O多路复用

匿名 (未验证) 提交于 2019-12-02 23:51:01
1、使用场景   IO多路复用是指内核一旦发现进程指定的一个或者多个IO条件准备读取,它就通知该进程。IO多路复用适用如下场合:   (1)当客户处理多个描述字时(一般是交互式输入和网络套接口),必须使用I/O复用。   (2)当一个客户同时处理多个套接口时,而这种情况是可能的,但很少出现。   (3)如果一个TCP服务器既要处理监听套接口,又要处理已连接套接口,一般也要用到I/O复用。   (4)如果一个服务器即要处理TCP,又要处理UDP,一般要使用I/O复用。   (5)如果一个服务器要处理多个服务或多个协议,一般要使用I/O复用。   与多进程和多线程技术相比,I/O多路复用技术的最大优势是系统开销小,系统不必创建进程/线程,也不必维护这些进程/线程,从而大大减小了系统的开销。 不同IO模式比较: select poll 移植性好,但单进程监视的文件数过多会性能不佳,不适合用于大并发 select的问题: (1)被监控的fds集合限制为1024 (2)fds集合需要从用户空间拷贝到内核空间 (3)当被监控的fds中某些有数据可读的时候,无法直接从通知中得到有可读事件的fds列表,而需要遍历整个fds来收集 poll使用pollfd结构而不是select的fd_set结构,解决问题(1) 水平触发,边缘触发:通知进程的方式 1. LTģʽ LT(level triggered

【I/O多路复用】select系统调用

匿名 (未验证) 提交于 2019-12-02 23:49:02
版权声明:署名,允许他人基于本文进行创作,且必须基于与原先许可协议相同的许可协议分发本文 ( Creative Commons ) 文章目录 【1】函数原型 【2】各个参数含义 【3】简单理解fd_set结构 【4】select模型的特点 【5】select函数的使用过程 【6】程序示例 【7】select的缺点 【1】函数原型 # include <sys/select.h> int select ( int maxfdp , fd_set * readfds , fd_set * writefds , fd_set * errorfds , struct timeval * timeout ) ; 【2】各个参数含义 int maxfdp 是一个整数值,是指 集合中所有文件描述符的范围 ,即所有文件描述符的最大值加1,因为文件描述符是从0开始的。 struct fd_set 可以理解为一个集合,这个集合中存放的是文件描述符(file descriptor),即文件句柄。 readfds 需要检测 可读文件描述符 的集合; writefds 需要检测 可写文件描述符 的集合; errorfds 需要检测的 异常文件描述符 的集合。 fd_set集合可以通过一些宏由人为来操作。如下: # include <sys/select.h> FD_ZERO ( fd_set * fdset

【I/O多路复用】epoll系统调用

匿名 (未验证) 提交于 2019-12-02 23:49:02
版权声明:署名,允许他人基于本文进行创作,且必须基于与原先许可协议相同的许可协议分发本文 ( Creative Commons ) 文章目录 【1】epoll相关的系统调用 epoll_create() epoll_ctl() epoll_wait() 【2】代码示例 【1】epoll相关的系统调用 epoll是Linux特有的I/O复用函数。它在实现和使用上与select、poll有很大差异。 首先 , epoll使用一组函数来完成任务 ,而不是单个函数。 其次 , epoll 把用户关心的文件描述符上的事件放在内核里的一个事件表中 ,从而无须像select和poll那样每次调用都要重复传人文件描述符集或事件集。 但是 epoll需要使用一个额外的文件描述符,来唯一标识内核中的这个事件表。 epoll_create() 这个文件描述符使用如下epoll create函数来创建: # include <sys/epoll.h> int epoll_create ( int size ) 其中 size参数现在并不起作用,只是给内核一个提示,告诉它事件表需要多大。 返回值 该函数返回一个文件描述符,用作其他所有epoll系统调用的第一个参数,用来指定要访问的内核事件表。 epoll_ctl() # include <sys/epoll.h> int epoll_ctl ( int

Day 36 阻塞与非阻塞 多路复用

匿名 (未验证) 提交于 2019-12-02 23:47:01
Ŀ¼ 模型即解决某个问题的固定套路 I/O 指的是输入输出 IO的问题:当我们要输入数据或输出数据通常很长一段时间,当然是对于CPU而言 在等待输入的过程中,CPU就处于闲置状态,没事干,造成了资源浪费 注意:IO其实有很多类型 例如 socket网络IO,内存到内存的copy,等待键盘输入,对比起来socket网络IO需要等待的时间是最长的,这也是咱们重点关注的地方, 学习IO模型要干什么?就是在等待IO操作的过程中利用CPU做别的事情, 操作系统有两种状态: 内核态和用户态 ,当操作系统需要控制硬件时例如接受网卡上的数据,必须先转换到内核态,接受完数据后,要把数据从操作系统缓冲器copy到应用程序的缓冲区,从内核态转为用户态, 涉及到的步骤 buffer 缓冲 cache 缓存 将数据读入到内存所使用的空间叫做**缓冲** 从内存中读取数据存放数据的空间叫作**缓存**** 缓冲是为了降低IO次数 缓存是为了提高读取效率 wait_data copy_data recv accept 需要经历 wait->copy send 只需要经历copy 默认情况下 TCP程序就是阻塞IO模型 1.执行BLOCK将进程阻塞 2.等待数据 3.copy数据 4.唤醒进程,继续,执行 该模型提高效率方式,当你执行recv/accept会进入wait_data的阶段,

epoll实现多路复用

匿名 (未验证) 提交于 2019-12-02 23:40:02
程序阻塞的过程 假设系统目前运行了三个进程 A B C 进程A正在运行一下socket程序 server = socket . socket () server . bind (( "127.0.0.1" , 1688 )) server . listen () server . accept () 1.系统会创建文件描述符指向一个socket对象 ,其包含了读写缓冲区,已经进行等待队列 2.当执行到accept / recv 时系统会讲进程A 从工作队列中移除 3.将进程A的引用添加到 socket对象的等待队列中 进程的唤醒 1.当网卡收到数据后会现将数据写入到缓冲区 2.发送中断信号给CPU 3.CPU执行中断程序,将数据从内核copy到socket的缓冲区 4.唤醒进程,即将进程A切换到就绪态,同时从socket的等待队列中移除这个进程引用 用select来监控多个socket select的实现思路比较直接 1.先将所有socket放到一个列表中, 2.遍历这个列表将进程A 添加到每个socket的等待队列中 然后阻塞进程 3.当数据到达时,cpu执行中断程序将数据copy给socket 同时唤醒处于等待队列中的进程A为了防止重复添加等待队列 还需要移除已经存在的进程A 4.进程A唤醒后 由于不清楚那个socket有数据,所以需要遍历一遍所有socket列表 缺点: 1

nginx IO模型

折月煮酒 提交于 2019-12-02 23:27:42
今天下班早些来普及下nginx io模型: 用户空间与内核空间: 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方)。操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。为了保证用户进程不能直接操作内核(kernel),保证内核的安全,操作系统将虚拟空间划分为两部分,一部分为内核空间,一部分为用户空间。针对linux操作系统而言,将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称为内核空间,而将较低的3G字节(从虚拟地址0x00000000到0xBFFFFFFF),供各个进程使用,称为用户空间。 进程切换: 为了控制进程的执行,内核必须有能力挂起正在CPU上运行的进程,并恢复以前挂起的某个进程的执行。这种行为被称为进程切换。因此可以说,任何进程都是在操作系统内核的支持下运行的,是与内核紧密相关的。 从一个进程的运行转到另一个进程上运行,这个过程中经过下面这些变化: 保存处理机上下文,包括程序计数器和其他寄存器。 更新PCB信息。 把进程的PCB移入相应的队列,如就绪、在某事件阻塞等队列。 选择另一个进程执行,并更新其PCB。 更新内存管理的数据结构。 恢复处理机上下文。 注:总而言之就是很耗资源,具体的可以参考这篇文章: http:/

IO模型

匿名 (未验证) 提交于 2019-12-02 23:05:13
什么是IO模型? IO指的是输入输出,其执行速度非常慢 模型,只固定的套路 IO模型就是指实现输入输出的套路 IO的分类 1.本地IO 指的是输入输出到本地计算机 如:写入硬盘 2.网络IO 指的是输入输出到网络中的计算机,速度远比本地IO慢 网络IO输入输出过程 IO模型的分类 (重点) 1.阻塞型IO    之前学习的IO操作除了gevent都是阻塞型的    1.可以利用多线程来提高IO      线程不能太多,会造成内存溢出    2.线程池可以解决下线程太多问题      但如果线程池达到最大数,其他客户端将进入等待    3.在单线程下并发来处理 可以使单核下的效率最高 2.非阻塞IO 非阻塞IO的服务器 import socket server = socket.socket() server.bind(('192.168.1.67',4396)) server.listen() #设置为非阻塞IO server.setblocking(False) #存放所有连接过来的客户端 clients = [] while True: try: client,addr = server.accept() print('连入了一个客户端!') clients.append(client) except BlockingIOError: #已经关闭的客户端 close_c = [

Python IO多路复用

匿名 (未验证) 提交于 2019-12-02 22:51:30
多个socket是否已经发生变化,(是否已经连接成功/是否已经获得数据)(可读/可写) 实现: IO多路复用 非阻塞 代码如下: import socket import select client1 = socket.socket() client1.setblocking(False) # 将原本链接阻塞,修改为非阻塞 # 百度创建链接,阻塞 try: client1.connect(('www.baidu.com',80)) except BlockingIOError: pass client2 = socket.socket() client2.setblocking(False) # 将原本链接阻塞,修改为不阻塞 # 百度创建链接,阻塞 try: client2.connect(('www.sogou.com',80)) except BlockingIOError: pass client3 = socket.socket() client3.setblocking(False) # 将原本链接阻塞,修改为不阻塞 # 百度创建链接,阻塞 try: client3.connect(('www.oldboyedu.com',80)) except BlockingIOError: pass socket_list = [client1,client2,client3]

select模块(I/O多路复用)

匿名 (未验证) 提交于 2019-12-02 22:51:30
Python中的select模块专注于I/O多路复用,提供了select poll epoll三个方法(其中后两个在Linux中可用,windows仅支持select),另外也提供了kqueue方法(freeBSD系统) r_list,w_list,e_list = select.select(rlist, wlist, xlist, [timeout]) 三个参数 rlist wait until ready for reading(等待,直到准备阅读) 在tcp协议中accept与recv都存在一个等待的过程他们要等数据过来才会执行消息发来后他会进入一个可读状态 wlist wait until ready for writing(等待,直到准备写) 在tcp协议send不存在一个等待的过程,他会直接把信息丢到缓存,然后这时候会进入可写状态 xlist wait for an “exceptional condition”(等待,有异常情况) timeout 当超时时间为空,则select会一直阻塞,直到监听的句柄发生变化 当超时时间 = n(正整数)时,那么如果监听的句柄均无任何变化,则select会阻塞n秒,之后返回三个空列表,如果监听的句柄有变化,则直接执行。 示例: 服务端 import socket import time import select s =