IO多路复用

在前一篇文章中,我们实现了通过非阻塞套接字的并发服务,但是这种实现方式是有很多问题的。

一、CPU资源的极大浪费;

二、如果没有连接那么,accept()和recv()都在做无用功;

三、对BlockIOError的处理也是在做无用功。

针对以上问题,现在我们使用IO多路复用的技术来实现并发的服务。

什么是IO多路复用

IO多路复用是指内核一旦发现进程指定的一个或者多个IO条件准备读取,它就通知该进程。IO多路复用适用如下场合:

1.当客户需要处理多个描述符时,必须使用I/O复用。

2.当一个客户同时处理多个套接口时,而这种情况是可能的,但很少出现。

3.如果一个TCP服务器既要处理监听套接口,又要处理已连接套接口。

4.如果一个服务器即要处理TCP,又要处理UDP。

5.如果一个服务器要处理多个服务或多个协议
目前支持I/O多路复用的系统调用有 select,pselect,poll,epoll但select,pselect,poll,epoll本质上都是同步I/O。其中epoll时Linux系统独有的。也是要主要介绍的。

select

Python的select()方法直接调用操作系统的IO接口,它监控sockets,open files, and pipes(所有带fileno()方法的文件句柄)何时变成readable 和writeable, 或者通信错误,select()使得同时监控多个连接变的简单,并且这比写一个长循环来等待和监控多客户端连接要高效,因为select直接通过操作系统提供的C的网络接口进行操作,而不是通过Python的解释器。

select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点。select的一 个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,可以通过修改宏定义甚至重新编译内核的方式提升这一限制,但是这样会造成效率的降低

select(rlist, wlist, xlist, timeout=None)

select()方法接收并监控3个通信列表, 第一个rlist监控所有要进来的输入数据,第二个wlist是监控所有要发出去的输出数据,第三个监控异常错误数据,第四个设置指定等待时间,如果想立即返回,设为null即可,最后需要创建2个列表来包含输入和输出信息来传给select(),让select方法通过内核去监控,然后生成三个实例。zaipython中直接导入select使用。

epoll

epoll的方式,这种效率更高,但是这种方式在Windows下不支持,在Linux是支持的,selectors模块就是默认使用就是epoll,但是如果在windows系统上使用selectors模块,就会找不到epoll,从而使用select。

服务端代码:

import socket
import selectors
server=socket.socket()
server.bind(('0.0.0.0',8899))
server.listen()
epoll=selectors.DefaultSelector()
def recv_func(conn):
    data=conn.recv(1024)
    if data==b'':
        epoll.unregister(conn)
        conn.close()
    else:
        print("接收到数据:>>>",data)
        conn.send(data)
def server_func(ser):
    conn,addr=ser.accept()
    print("连接处理!")
    epoll.register(conn,selectors.EVENT_READ,recv_func)
epoll.register(server,selectors.EVENT_READ,server_func)
while True:
    events=epoll.select()
    for key,value in events:
        callback=key.data
        sock=key.fileobj
        callback(sock)

客户端代码

import socket
client=socket.socket()
client.connect(('127.0.0.1',8899))
while True:
    data=input("请输入传送的数据:>>>>")
    client.send(data.encode())
    print("接收到的数据:>>>",client.recv(1024).decode())
 
原文地址:https://www.cnblogs.com/austinjoe/p/9661502.html