二十二.Python_IO模型

Python_IO模型

#IO模型

#同步IO     存在线程等待,就叫做同步IO
    #阻塞IO
        #Socket.accept()  用户态请求内核态,内核态等待客户端,用户态被挂起,进入阻塞状态,这种现象就叫做阻塞IO
    #非阻塞IO
        #socket.setblocking(false) 用户态请求内核态,内核态查看是否有客户端请求,当即向用户态返回结果,用户态接受结果,继续执行,不会被挂起,这种现象叫做非阻塞IO
    #IO多路复用
    #模块:    Windows Python:
            #     提供: select
            # Mac Python:
            #     提供: select
            # Linux Python:
            #     提供: select、poll、epoll
        #利用select等模块请求内核态,此时,用户态被挂起,内核态等待,直到有客户端请求,内核态返回结果,用户态执行accept(),将内核态的客户端连接复制到用户态,
        #多路复用实现了服务器并发的功能

        #水平触发(select属于水平触发)
        #________--------_______   下划线为0,横线为1,当执行到横线1这段时,会触发内核态返回,叫做水平触发
        #边缘触发
        #______  ------  ______    当执行到下划线到横线之间的这段距离时,触发内核态返回,叫做边缘触发
#异步IO    线程0阻塞,叫做异步IO

 #同步IO

 #IO多路复用

    #select模块

#select 模块
#采用select方式IO多路复用请求的模块,支持所有操作系统
#缺点:相对于epoll,效率不高


#使用
#s=select.select([sock,][][])
#创建select多路复用,sock是个socket对象,[socket,]是个列表对象,可以实现用户态向内核态请求多个等待对象,是实现IO并发的关键
#
#导入select模块和socket模块
import select,socket
#创建TCP socket
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#绑定
sock.bind(("127.0.0.1",8080))
#监听
sock.listen(5)

print(sock)
print("the server is start...")

sock_tuple=[sock,]
while 1:
    #创建select多路复用,等待sock_tuple列表里的所有对象,
    # 任意一个对象返回结果,内核态就会返回该对象,
    # select是通过循环访问实现的,epoll模块是通过自报家门的方式,可以直接获取到是哪个对象获取了信息,
    # 相对于select效率更高
    s=select.select(sock_tuple,[],[])[0][0]
    #判断是否是服务器对象,有客户端请求访问
    if s==sock:
        #从内核态获取客户端的连接到用户态
        conn,add=s.accept()
        #将获取的新的客户端的连接,加入到多路复用请求内核态的对象列表中
        sock_tuple.append(conn)
    else:
        try:
            #接收客户端的信息
            data=s.recv(1024).decode("utf-8")
            #发送信息到客户端
            s.send(data.upper().encode("utf-8"))
        except Exception as e:
            #出现异常,将客户端对象从内核态等待的对象列表中移除
            sock_tuple.remove(s)

 #selectors模块

#selectors
#是一个根据操作系统,自动选择select,poll,epoll方式的IO多路复用的模块

#使用
#sel=selectors.DefaultSelector()  创建Selectors 对象
#sel.register(sock,selectors.EVENT_READ,acce)  注册一个IO多路复用的事件,如果sock对象,有人请求,就调用acce方法
#key,mask=sel.selector()    #开始请求列表里的所有对象,到内核态,内核态获取到关于此对象的信息,返回到用户态,key(data,fileobj),mask
#key.data 获取关于此对象请求成功的回调函数  key.fileobj  关于收到请求信息的对象
#调用关于此对象的回调函数  ket.data(key.fileobj,mask)
#sel.unregister(sock)  取消sock对象的多路复用事件

import selectors,socket

#内核态取回客户端请求连接到用户态的函数
def acce(sock,mask):
    conn,addr=sock.accept()
    conn.setblocking(False)
    #注册新的客户端连接到等待集合对象
    sel.register(conn,selectors.EVENT_READ,talk)
#连接读写的函数
def talk(conn,mask):
    try:
        data=conn.recv(1024).decode("utf-8")
        conn.sendall(data.encode("utf-8"))
    except Exception as e:
        sel.unregister(conn)
#创建socket对象
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#绑定
sock.bind(("127.0.0.1",8080))
#监听
sock.listen(5)
#将socket设为非阻塞
sock.setblocking(False)
#创建selectors对象
sel=selectors.DefaultSelector()
#将sock注册为selectors的水平事件触发,回调函数为acce
sel.register(sock,selectors.EVENT_READ,acce)

print("the server is start..")
while 1:
    #循环请求内核态关于注册的对象是否有程序请求,如果有程序请求该对象,该对象就会从内核态返回
    events=sel.select()
    #获取从内核态返回的数据,包括data回调函数,fileob注册对象以及mask
    for key,mask in events:
        #获取关于此对象等待成功的回调函数
        fun=key.data
        #执行该回调函数,参数为key.fileobj 触发该事件对象,mask参数
        fun(key.fileobj,mask)

#异步IO

异步IO
0阻塞,没有等待

猜你喜欢

转载自blog.csdn.net/qq_39663113/article/details/85949246
今日推荐