IO 多路复用

本文介绍了IO多路复用相关知识。先区分了IO密集型和计算密集型程序,接着阐述了IO分类,包括阻塞IO、非阻塞IO和IO多路复用,说明了阻塞IO的两种阻塞情况及非阻塞IO的特点。重点讲解了IO多路复用的定义、编程实现步骤及具体方案,如select、poll、epoll。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

IO 多路复用

IO密集型程序 : 在程序执行过程中存在大量IO操作,而cpu运算操作较少。消耗cpu较少,运行效率较低

计算密集型程序(cpu密集型程序):在程序执行中cpu运算较多,IO操作相对较少。消耗cpu大,运行速度快

IO分类:

  • 阻塞IO
  • 非阻塞IO
  • IO多路复用

阻塞IO:是IO的默认形态,是效率较低的一种IO情形。

阻塞情况:

  1. 因为某种条件没有达成造成的阻塞

    e.g. accept input recv

  2. 处理IO数据传输时间较长形成的阻塞

    e.g. 网络传输过程,文件读写过程

非阻塞IO :通过修改IO事件的属性,使其变为非阻塞状态。比如:超时检测

*非阻塞IO往往和循环判断一起使用

IO多路复用

定义 : 同时监控多个IO事件,当哪个IO事件准备就绪就执行哪个IO事件。以此形成可用同时操作多个IO的并发行为,避免一个IO阻塞,造成所有IO都无法执行。

IO多路复用的编程实现

  1. 将IO设置为关注IO
  2. 将关注IO提交给内核监测
  3. 处理内核给我们反馈准备就绪的IO

具体方案:
select ——> windows linux unix

poll ——> linux unix

epoll ——> linux unix

from select import *

rs,ws,xs = select(rlist, wlist, xlist[, timeout])
功能: 监控IO事件,阻塞等待IO事件发生
参数: rlist   列表   存放我们监控等待处理的IO事件
      wlist   列表   存放我们要主动操作的IO事件
      xlist   列表   我们要关注出错处理的IO事件
      timeout  超时时间
返回值:rs  列表   rlist中准备就绪的IO
       ws  列表   wlist中准备就绪的IO
	   xs  列表   xlist中准备就绪的IO

注意 : 1. rlist有已经准备就绪的IO事件,select会立即返回给rs
	   2. IO多路复用占用计算机资源少,io效率高
    
poll

1.创建poll对象
p = poll()

2.添加注册事件
p.register(s,POLLIN | POLLERR)

POLLIN   POLLOUT  POLLERR  POLLHUP  POLLNVAL
rlist    wlist    xlist    断开     无效数据

p.unregister(s) 从关注事件中移除

3. 阻塞等待IO发生
events = p.poll()
功能 : 阻塞等待IO发生
返回值 : events 是一个列表,列表中给每一个元素都是一个元组,代表一个发生的IO事件
[(fileno,event),(fileno,event),(fileno,event)...]
fileno: 就绪IO的文件描述符
event: 具体就绪IO事件

* 需要通过文件描述符(fileno)找到对应的IO对象,所以需要建立映射关系 {s.fileno() : s}

4. 处理具体的IO

epoll方法
使用方法:基本与poll方法相同

epoll 和 poll的区别:
1. epoll 的效率要比 poll和select 高
2. epoll 的事件触发方式更多
from socket import * 
from select import *

#创建套接字作为我们关注的IO
s = socket()
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
s.bind(('0.0.0.0',8888))
s.listen(5)

#创建poll对象
p = poll()

#fileno ---> IO对象的字典
fdmap = {s.fileno():s}

#注册关注的IO
p.register(s,POLLIN | POLLERR)

while True:
    #进行IO监控
    events = p.poll()
    for fd,event in events:
        if fd == s.fileno():
            c,addr = fdmap[fd].accept()
            print("Connect from",addr)
            #添加新的关注事件
            p.register(c,POLLIN | POLLHUP)
            fdmap[c.fileno()] = c
        elif event & POLLIN:    
            data = fdmap[fd].recv(1024)
            if not data:
                #客户端退出,从关注事件移除
                p.unregister(fd)
                fdmap[fd].close()
                del fdmap[fd]
            else:
                print(data.decode())
                fdmap[fd].send(b'Receive')
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值