Python之进程+线程+协程(异步、selectors模块、阻塞、非阻塞IO)


本篇文字是关于IO多路复用的更深入一步的总结,上一篇 Python之进程+线程+协程(事件驱动模型、IO多路复用、select与epoll)对IO多路复用进行了概念性的分析,本篇则是对阻塞IO、非阻塞IO、与异步进行通俗性的比较和归纳。还有另外一种无阻塞IO,即为异步IO,用selectors模块来实现

一、IO多路复用

1、阻塞IO: 不停监听,遇到用户输入时,会一直卡在那里,直到接收了外部数据

2、非阻塞IO: 也可以说是间断监听,过一段时间去监听一次,不会持续卡在那里,但仍然有阻塞,只是没那么严重

3、异步最大的特点: 全程无阻塞

4、selectors模块(异步IO模块): python封装好的一个IO多路复用的模块,等待用户输入的同时让CPU能够去处理其他任务,不会卡在那里,不会有任何阻塞

二、selectors模块

用一个实例来总结selectors模块,每段代码的逻辑在旁边都注有详细的解释了,这里就不拆出来分析了。要用到socket套接字,而且重点在服务端的逻辑,客户端只是正常收发消息就够了。
1、服务端:

import selectors  #导入selectors模块
import socket

#创建selectors对象
sel = selectors.DefaultSelector()

#接收信息函数
def accept(sock, mask):
    conn, addr = sock.accept()  #接收客户端的链接和地址
    print('accepted', conn, 'from', addr)  #输出收到的链接和地址
    conn.setblocking(False)  #设置为无阻塞IO
    sel.register(conn, selectors.EVENT_READ, read)
    #注册selector对象,将客户端链接和read函数绑定,执行read函数

#读取信息
def read(conn, mask):
    try:
        data = conn.recv(1000)  #用客户端的链接读取客户端传来的信息
        if not data:
            raise Exception     #如果监听对象里面的内容为空就触发Excetption异常
        #不为空就执行输出消息
        print('echoing', repr(data), 'to', conn)
        conn.send(data)  #输出消息后,给客户端发送一条消息,repr(data)
    except Exception as e:  #为空就接触selector的注册
        print('closing', conn)
        sel.unregister(conn)  
        conn.close()

#创建套接字对象
sock = socket.socket()
sock.bind(('localhost', 8090))  #绑定端口
sock.listen(100)  #监听端口
sock.setblocking(False)  #设置IO为非阻塞IO

#注册selector对象,
#即将selector将socket对象和accept函数绑定
sel.register(sock, selectors.EVENT_READ, accept)
print("server端已启动......")

#执行绑定的对象,开启监听
while True:
    #将events作为监听结果的接收器,包含[sock,,conn1,conn2,conn3......]
    events = sel.select()
    
    for key, mask in events:
        callback = key.data
        callback(key.fileobj, mask)
        #第一次的key.data就是sock触发的那个accept函数,执行accept函数传入两个参数
        #第二次的key.data是read函数
        #第一次key.fileobj就是服务端创建的sock,一个socket对象
        #第二次key.fileobj是conn

2、客户端:

import socket

sk=socket.socket()

sk.connect(("127.0.0.1",8090))
while 1:
    inp=input(">>>")  #让用户输入内容
    sk.send(inp.encode("utf8"))  #发送消息
    data=sk.recv(1024)  #接收消息
    print(data.decode("utf8"))

3、参考结果:
selectors模块
可以看到,三个同时聊天,中途可以随意切换,并不会出现任何IO阻塞,这也就异步的效果,得益于selectors这个python的套装模块

猜你喜欢

转载自blog.csdn.net/Viewinfinitely/article/details/105642558
今日推荐