同步阻塞: 立即返回最终结果
同步不阻塞: 等待 返回最终结果
同步,异步,与 阻塞,非阻塞 不相关
同步 异步 ——> 强调的是结果
阻塞 非阻塞 ——> 强调的是时间,是否等待
同步与异步的区别:调用者是否得到了想要的结果
同步 一直执行到返回结果
异步直接返回,但不是最终结果。调用者不能通过这种调用得到结果,还要通过被调用者,使用其他方式通知调用者,来拿到最终结果
阻塞与非阻塞的区别在于 调用者是否在阻塞期间能做彼得事
阻塞,调用者只能 等到出结果为止
非阻塞, 调用者可以执行别的函数,不用一直等
同步IO,异步IO,IO多路复用
IO两个阶段:
1,数据准备阶段
2,内核空间复制回用户进程缓冲区阶段
发送IO的时候
内核从输入设备读写数据
进程从内核复制数据
同步IO
同步IO模型包括,阻塞IO,非阻塞IO,IO多路复用
阻塞IO
进程等待(阻塞),直到读写完成(全程等待)
read/write
非阻塞IO
进程调用read操作,如果IO设备没有准备好,立即返回ERROR,进程不阻塞,用户可以在此发起系统调用,如歌内核已经准备好,就阻塞,然后复制数据到用户空间
第一阶段,重复检查数据是否准备好,非阻塞
第二阶段,阻塞,等待服务端数据拷贝完毕为止
IO多路复用:
同时监控多个IO,有一个准备好了就不需要等了,开始处理,提高了同时处理IO的能力
select所有平台支持
select 作为一个监控,可以帮你看着一个进程操作是否满足条件,若满足条件,会通知用户进程
以select为例,将关注的IO操作 告诉select函数并调用,进程阻塞,内核“监视”select关注的文件描述符fd,
被关注的任何一个fd对应的IO准备好了数据,select返回,在使用read将数据复制到用户进程、
异步IO:
进程发起异步IO请求,立即返回一个状态,内核完成IO的两个阶段,内核给进程发送信号
python中IO多路复用
python的select库
实现了select库,底层的IO多路复用模块
开发平台的选择,根据不同操作系统自行选择支持的技术,这样做会提高IO处理的性能
selectors库
3.4版本提供足够库,高级io复用
selectors.DefaultSelector 返回当前平台最有效,性能最高的实现
没有实现windows下的IOCP,windows下退化为select
abstractmethod register(fileobj,events,data = None)
为selection注册一个文件对象,监视它的IO事件
fileobj被监控文件对象,例如socket对象
events事件,该文件对象必须等待的事件
data 本例中关联的方法,监控其状态改变后的下一步操作
将聊天软件 改写成IO多路复用的模式
#将ChatServer改为IO多路复用的方式
#从而不需要多线程的启动了
import socket import selectors import threading import logging logging.basicConfig(format="%(message)s ",level=logging.INFO) class Chat_Server: def __init__(self,ip="127.0.0.1",port = 7888): self.sock = socket.socket() self.addr = (ip,port) self.event = threading.Event() self.selector = selectors.DefaultSelector() def start(self): self.sock.bind(self.addr) self.sock.listen() self.sock.setblocking(False) self.selector.register(self.sock,selectors.EVENT_READ,self._accept) #指向accept,说明状态后需要执行的操作,只做监控,并不执行 threading.Thread(target=self._run).start() def _run(self): while not self.event.is_set(): events = self.selector.select(1) #将监控到的数据,传给一个容器,有容器去回调他们该做的操作 for key,mask in events: callback = key.data #key.data 指向的 是监控状态发生改变的事件该执行的函数 callback(key.fileobj) #用该函数,传入一个socket对象,达到其结果 def _accept(self,sock:socket.socket): conn,client = sock.accept() conn.setblocking(False) key = self.selector.register(conn,selectors.EVENT_READ,self._recv) ##recv,说明状态后需要执行的操作,只做监控,并不执行 def _recv(self,conn:socket.socket): data = conn.recv(1024).decode().strip() logging.info(data) # conn.send(data.encode()) e = threading.Event() cs = Chat_Server() cs.start() while not e.wait(1): cmd = input(">>>").strip() if cmd == "quit": cs.stop() e.wait(3) break