事件驱动,IO模型1.事件驱动;是一种编程方式(编程思想),与编程语言不要紧 事件之间互不影响,谁触发谁执行 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p onclick="func()">点我呀</p> <script> function func() { alert('eric210') } </script> </body> </html>传统事件监听的方式:(占用cpu资源) def f(): pass while 1: 鼠标检测2.IO模型: IO (计算机用语):I/O输入/输出(Input/Output),分为IO设备和IO接口两个部分。 在POSIX兼容的系统上,例如Linux系统 [1], I/O操做能够有多种方式,好比DIO(Direct I/O),AIO(Asynchronous I/O,异步I/O),Memory-Mapped I/O(内存映射I/O)等,不一样 的I/O方式有不一样的实现方式和性能,在不一样的应用中能够按状况选择不一样的I/O方式。 IO多路复用:前面是用协程实现的IO阻塞自动切换,而协程的原理和在事件驱动的状况下IO的自动阻塞的切换的学名叫===》IO多路复用 socketserver,多个客户端链接,单线程下实现并发效果,就是多路复用。 同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,区别是什么,不一样的人在不一样的上下文给出的答案是不一样的,因此先限定一下本文上下 文本文讨论的背景是Linux环境下的networkIO。 (1)用户空间和内核空间:用户空间没法访问内核空间 (2)进程切换:切换过程大量消耗时间 (3)进程的阻塞 (4)文件描述 (5)缓存I/O:很是消耗资源3.Stevens在文章中比较了五种IO Mode: (1)blocking IO(阻塞IO):blockingIO的特色就是在IO执行的两个阶段都被block了(阻塞,就是调用我(函数),我(函数) 没有接收完数据或者没有获得结果以前,我不会返回。) import socket sk=socket.socket() sk.bind() sk.listen(3) # sk.setblocking()#过滤阻塞IO con,add=sk.accept() con.recv() con.send() 弊端:进程全程阻塞状态,什么都干不了 实例: #server端 #author: wylkjj #date:2019/5/20 import socket sk = socket.socket() address=('127.0.0.1',8080) sk.bind(address) sk.listen(3) sk.setblocking(False) import time while 1: try: conn,add=sk.accept() while 1: data=conn.recv(1024) print(data.decode('utf8')) conn.sendall(data) conn.close() except Exception as e: print('error:',e) time.sleep(3) #clinet端 #author: wylkjj #date:2019/5/20 import socket sk = socket.socket() address=('127.0.0.1',8080) sk.connect(address) while 1: # inp=input(">>>:") sk.sendall('hello'.encode('utf8')) data=sk.recv(1024) print(data.decode('utf8')) (2)nonblocking IO(非阻塞IO):copy状态也是阻塞的,可是其它状态不是阻塞的,例如recv()屡次发送询问(非阻塞,就是调 用我(函数),我(函数)当即返回,经过select通知调用者) 弊端:数据延迟,数据不能及时拿到 (3)IO multiplexing(IO多路复用):这个词会陌生,可是select,epoll大概会明白,有些地方称这种IO方式为event driven IO select/epoll的好处在于单个process能够同时处理多个网络链接的IO基本原理就是select/epoll这个function会不断的轮询所 负责的全部socket,当某个socket有数据到达了,就通知用户进程 select优势:能够同时监听多个文件描述符实现并发效果。(跨平台) epoll:大多数都用epoll,也能够同时监听多个文件描述符实现并发效果。 主权:因此IO多路复用的模型也属于同步IO (4)signal driven IO(信号驱动IO,实际中不经常使用) (5)asynchronous IO(异步IO):进程再也不阻塞,注:只要有一点阻塞就不是异步IO(异步,就是我调用一个功能,不须要知道该 功能结果,该功能有结果后通知我(回调通知)。) synchronous IO(同步IO):除异步IO上面的都属于同步IO(同步,就是我调用一个功能,该功能没有结束前,我死等结果。)4. 注意区别:他们针对的对象是不一样的 同步IO和异步IO的区别就在于:数据拷贝的时候进程是否阻塞 阻塞IO和非阻塞IO的区别就在于:应用程序的调用是否当即返回5.IO multiplexing(IO多路复用):select,epoll select:r,w,e=select.select([sk1,sk2],[],[],5),5表示监听5秒,5秒一打印 select实例1:(select是一种水平触发) #author: wylkjj #date:2019/5/20 #server端 import socket,select sk1 = socket.socket() address1=('127.0.0.1',8080) sk1.bind(address1) sk1.listen(3) sk2=socket.socket() address2=('127.0.0.1',8081) sk2.bind(address2) sk2.listen(3) while True: r,w,e=select.select([sk1,sk2],[],[]) print('rrr') for obj in r: conn,addr=obj.accept()#conn会变,临时分配,可是链接的socket对象是同样的 print('conn',conn) print("hellow") print('r:>>',r) #author: wylkjj #date:2019/5/20 #clinet1端 import socket sk = socket.socket() address=('127.0.0.1',8080) sk.connect(address) while 1: data=sk.recv(1024) print(data.decode('utf8')) inp=input(">>>:") sk.sendall(inp.encode('utf8')) #author: wylkjj #date:2019/5/20 #clinet2端 import socket sk = socket.socket() address=('127.0.0.1',8081) sk.connect(address) while 1: data=sk.recv(1024) print(data.decode('utf8')) inp=input(">>>:") sk.sendall(inp.encode('utf8')) 实例2:clinet同上同样 #author: wylkjj #date:2019/5/20 #server端 import socket,select sk1 = socket.socket() address1=('127.0.0.1',8080) sk1.bind(address1) sk1.listen(3) sk2=socket.socket() address2=('127.0.0.1',8081) sk2.bind(address2) sk2.listen(3) while True: r,w,e=select.select([sk1,sk2],[],[]) # print('rrr') for obj in r: conn,addr=obj.accept()#conn会变,临时分配,可是链接的socket对象是同样的 print('conn',conn) print("hellow") print('r:>>',r) epoll既能够采用水平触发,也能够采用边缘触发 水平触发:也就是只有高电平(1)或低电平(0)时才触发通知,只要再这两种状态就能获得新通知,只要有数据可读(描述符 就绪)那么水平触发的epoll就当即返回 边缘触发:只有电平发生变化(高电平到低电平,或者低电平到高电平)的时候才出发通知,即便有数据可读,可是没有新的IO 活动到来,epoll也不会当即返回。6.IO多路复用的并发聊天: 互动聊天: #author: wylkjj #date:2019/5/20 #模拟并发效果 #server端 import socket import select sk = socket.socket() address=('127.0.0.1',8800) sk.bind(address) sk.listen(3) inp=[sk,] while 1: inputs, outputs, errors = select.select(inp,[],[],) for obj in inputs: if obj==sk: conn,addr=sk.accept() print(conn) inp.append(conn) else: data=obj.recv(1024) print(data.decode('utf8')) Inputs=input('回答%s>>>'%inp.index(obj)) obj.sendall(Inputs.encode('utf8')) #author: wylkjj #date:2019/5/20 #clinet端 import socket,time sk = socket.socket() address=('127.0.0.1',8800) sk.connect(address) while 1: inp=input(">>>:") sk.sendall(inp.encode('utf8')) data = sk.recv(1024) print(data.decode('utf8')) #author: wylkjj #date:2019/5/20 #clinet端 import socket,time sk = socket.socket() address=('127.0.0.1',8800) sk.connect(address) while 1: inp=input(">>>:") sk.sendall(inp.encode('utf8')) data = sk.recv(1024) print(data.decode('utf8'))