Python3-事件驱动、IO模型和触发方式

事件驱动模型

传统编程线性模型

开始  ---->   代码块A ---->代码块B ---->代码块C 。。。。。。 结束

每一个代码块都有各自实现的功能,按照条件语句顺序判断执行,每一次运行顺序或许都不一样,它的控制流程是由获取的数据所和判断语句所决定的。编程

事件驱动程序模型

开始  ---->  初始化  ---->  等待

事件驱动器启动后,在等待事件触发,而后作出相应的程序执行效果。触发事件包括:输入信息、鼠标、敲击键盘、内部定时器等服务器


IO模型

synchronous 同步IO

一个进程在执行某个任务时,另一个进程必须等待其执行完毕,才能继续执行网络

所谓同步,就是在发出一个功能调用时,在没有获得结果以前,该调用就不会返回。按照这个定义,
其实绝大多数函数都是同步调用。可是通常而言,咱们在说同步、异步的时候,
特指那些须要其余部件协做或者须要必定时间完成的任务。

asynchronous 异步IO

当一个异步功能调用发出后,调用者不能马上获得结果多线程

当该异步功能完成后,经过状态、通知或回调来通知调用者。若是异步功能用状态来通知,
那么调用者就须要每隔必定时间检查一次,效率就很低(有些初学多线程编程的人,总喜欢用一个循环去检查某个变量的值,这实际上是一 种很严重的错误)。
若是是使用通知的方式,效率则很高,由于异步功能几乎不须要作额外的操做。至于回调函数,其实和通知没太多区别。

blocking 阻塞IO

调用结果返回以前,当前线程会被挂起并发

函数只有在获得结果以后才会
将阻塞的线程激活。有人也许会把阻塞调用和同步调用等同起来,实际上他是不一样的。对于同步调用来讲不少时候当前线程仍是激活的,只是从逻辑上当前函数没有返回而已。

non-blocking 非阻塞IO

和阻塞IO对立app

在不能马上获得结果以前也会马上返回,同时该函数不会阻塞当前线程

触发方式

水平触发

只有高电平(1)或低电平(0)的时候才触发通知,只要在这两种状态就能获得通知,只要有数据可读,那么水平触发的epoll就当即返回异步

边缘触发

只有电平发生变化(高电平到低电平,或者低电平到高电平)的时候才触发通知,有数据可读,但没有新的IO活动到来,epoll不会当即返回socket


multiplexing IO多路复用

select优缺点对比async

select:轮询方式,遍历每一个监听对象是否有数据变更,效率较低函数

epoll:主动响应,主动提交数据变更提高效率

select模块水平触发实现并发IO多路复用

服务端

# -*- coding:utf8 -*-
import socket,select
test = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#定义socket通讯方式和通讯协议。socket.AF_INET基于网络通讯,socket.SOCK_STREAM基于TCP协议
test.bind(('127.0.0.1',8000))                                   # 定义通讯ID
test.listen(5)                                                  # 定义最大通讯监听数
inputs = [test,]                                                #定义监听socket对象的列表
while True:
    r,w,e = select.select(inputs,[],[],5)                       # select监听 socket 对象,后跟时间单位为秒
    for obj in r:                                               # 遍历监听对象列表
        if obj == test:                                         # 判断监听对象是否和上次遍历同样
            conn,addr = obj.accept()                            # 被动接收套接字创建的链接
    print('accepted',conn,'from',addr)
            inputs.append(conn)                                 # 添加新socket对象到列表
        else:
            msg = obj.recv(1024)                                # 定义接收字节信息
            print('客户端发送的消息是:', msg)
            obj.send(msg.upper())                               # 定义发送消息
    print("服务监听中...")
服务监听中...
客户端发送的消息是: b'abc'
服务监听中...
客户端发送的消息是: b'aaa'
服务监听中...

客户端

# -*- coding:utf8 -*-
import socket
test = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#定义socket通讯方式和通讯协议。socket.AF_INET基于网络通讯,socket.SOCK_STREAM基于TCP协议
test.connect(('127.0.0.1',8000))                #定义通讯ID,服务器的地址和端口
while True:
    inp = input(">>>").strip()                  #用户输入发送内容
    test.sendall(inp.encode('utf-8'))              #定义发送内容
    data = test.recv(1024)                      #定义接收字节信息
    print('收到服务端的发来的消息是:',data)
>>>abc
收到服务端的发来的消息是: b'ABC'
>>>aaa
收到服务端的发来的消息是: b'AAA'
>>>

selectors模块实现并发IO多路复用

服务端

#-*- coding:utf-8 -*-
import selectors,socket
sel = selectors.DefaultSelector()                   # 操做系统自识别合适的IO多路复用方式

def accept(sock,mask):
    conn,addr = sock.accept()                       # 被动接收套接字创建的链接
    conn.setblocking(False)                         # 设置非阻塞
    sel.register(conn,selectors.EVENT_READ,read)    # conn 和 read 绑定,socket对象有活动调用accept方法
def read(conn,mask):
    try:                                            # 异常代码检测防止某个客户端断开链接致使服务终止
        data = conn.recv(1024)                      # 接收数据
        if not data:                                # 判断是否接收到数据
            raise Exception
        conn.send(data.upper())                     # 接收到数据并返回数据
    except Exception as e:                          # 万能异常
        sel.unregister(conn)                        # 没有接收到数据,解除conn绑定的函数
        conn.close()                                # 关闭链接

sock = socket.socket()                              # 建立socket对象
sock.bind(('127.0.0.1',8000))                       # 定义通讯ID绑定对象
sock.listen(100)                                    # 定义最大通讯监听数
sock.setblocking(False)                             # 设置非阻塞

sel.register(sock,selectors.EVENT_READ,accept)      # socket 和 accept 绑定,socket对象有活动调用accept方法

print("服务运行中....")
while True:
    events = sel.select()                           # 监听socket对象
    for key,mask in events:                         # 遍历events对象列表
        callback = key.data                         # 触发socket绑定的函数accept
        callback(key.fileobj,mask)                  # 监听到的有相应的socket对象
服务运行中....

客户端

# -*- coding:utf8 -*-
import socket
test = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#定义socket通讯方式和通讯协议。socket.AF_INET基于网络通讯,socket.SOCK_STREAM基于TCP协议
test.connect(('127.0.0.1',8000))                #定义通讯ID,服务器的地址和端口
while True:
    inp = input(">>>").strip()                  #用户输入发送内容
    test.sendall(inp.encode('utf-8'))           #定义发送内容
    data = test.recv(1024)                      #定义接收字节信息
    print('收到服务端的发来的消息是:',data)
>>>abc
收到服务端的发来的消息是: b'ABC'
>>>
相关文章
相关标签/搜索