事件驱动,IO模型

事件驱动,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'))
posted @ 2019-05-20 22:26  HashFlag  阅读(687)  评论(0编辑  收藏  举报