Python之io概念
""" 同步,异步: 强调结果,调用者最终是否得到想要的结构 阻塞非阻塞: 强调时间是否等待 io二个阶段 1.数据准备阶段 2.内核空间复制回用户空间缓冲区阶段 发生io时候 1.内核从输入设备读,写数据 2.进程从内核复制数据 io模型 1.同步io包括阻塞io,非阻塞io,io多路复用 阻塞io:进程等待(阻塞),直到读写完成 非阻塞io: 进程调用read操作,如果io没有准备好,立即返回error,进程不阻塞 用户可以再次发起系统调用,内核准备好,就阻塞,复制数据到用户空间 io多路复用: 就是同时监控多个io,有一个准备好,就不需要等待了开始处理,提高了同时处理io的功能 select所以的平台都支持,poll是对其的升级,epoll对poll的曾强增加回调机制,select最多监控 1024个fd,select轮询的方式,效率低下 epoll,fd没有上限,并且是回调机制,不需要遍历,效率高 2.异步io 进程发起异步io请求,立即返回,内核完成io的二个阶段,内核给进程发一个信号 linix aio的系统调用 """
''' abstractmethod register(fileobj,events,data=None) 为selector注册一个文件对象,监视他的io事件 fileobj被监视文件对象,例如socket events事件,该文件对象必须等待的事件 data可选的与此文件对象相关联的不透明数据,例如关联用来存储每个客户端的会话id event_read 可读0b01内核准备好输入输出设备,可以开始读了 event_write可写0b10内核准备好了,可以写了 '''
io多路复用
import selectors import socket #在winodws上使用的是select,移植到linux就是epoll #recv,send就是io操作 sel = selectors.DefaultSelector() def accept(sock, mask): conn, addr = sock.accept() # Should be ready print('accepted', conn, 'from', addr) conn.setblocking(False) sel.register(conn, selectors.EVENT_READ, read) #产生new_socket的时候调用read函数 def read(conn, mask): data = conn.recv(1000) # Should be ready if data: print('echoing', repr(data), 'to', conn) conn.send(data) # Hope it won't block else: print('closing', conn) sel.unregister(conn) conn.close() sock = socket.socket() #产生fileobj sock.bind(('localhost', 1234)) sock.listen(100) sock.setblocking(False) #非阻塞,要求 sel.register(sock, selectors.EVENT_READ, accept) ##参数fileobj,events,data=None(回调函数,或者数据) ''' 产生socket,就是有连接请求,传给回调函数执行 sock,selectors.EVENT_READ说明socket和读就绪后执行accept ''' # key = sel.register(sock, selectors.EVENT_READ, accept) key有四个属性,fileobj,fd,events,data while True: events = sel.select() #阻塞,直到events(读,写) for key, mask in events: #key有四个属性,fileobj,fd,envets,data(accept,read等回调函数) callback = key.data #当socket接入时,key.data = accept callback(key.fileobj, mask) #accept(key.fileobj,mask) ,key.ffileoj就是sock
import socket import threading import datetime import selectors class ChatServer: def __init__(self,ip='127.0.0.1',port=9999): 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) threading.Thread(target=self.select,daemon=True).start() def select(self): while not self.event.is_set(): events = self.selector.select() for key,mask in events: callback = key.data callback(key.fileobj) def accept(self,sock:socket.socket): conn,addr = sock.accept() conn.setblocking(False) self.selector.register(conn,selectors.EVENT_READ,self.receive) def receive(self,sock:socket.socket): data = sock.recv(1024) if data ==b"": self.selector.unregister() self.sock.close() return msg = '{}:{}\n{}\n'.format(*sock.getpeername(),data.decode()) for key in self.selector.get_map().values(): if key.data==self.receive: #排除self.accept key.fileobj.send(msg) def stop(self): self.event.set() fobjs = [] for fd,key in self.selector.get_map().items(): fobjs.append(key.fileobj) for fobj in fobjs: self.selector.unregister(fobj) fobj.close() self.selector.close() def main(): cs = ChatServer() cs.start() while True: cmd = input(">>>") if cmd == 'quit': cs.stop() break if __name__ == '__main__': main()
本文为原创文章,转载请标明出处