IO模型

什么是IO模型?

IO指的是输入输出,其执行速度非常慢

模型,只固定的套路

IO模型就是指实现输入输出的套路

IO的分类

1.本地IO 指的是输入输出到本地计算机 如:写入硬盘

2.网络IO 指的是输入输出到网络中的计算机,速度远比本地IO慢

网络IO输入输出过程

IO模型的分类(重点)

1.阻塞型IO

  之前学习的IO操作除了gevent都是阻塞型的

  1.可以利用多线程来提高IO

    线程不能太多,会造成内存溢出

  2.线程池可以解决下线程太多问题

    但如果线程池达到最大数,其他客户端将进入等待

  3.在单线程下并发来处理 可以使单核下的效率最高

2.非阻塞IO

非阻塞IO的服务器

import socket
server = socket.socket()
server.bind(('192.168.1.67',4396))
server.listen()
#设置为非阻塞IO
server.setblocking(False)
#存放所有连接过来的客户端
clients = []
while True:
    try:
        client,addr = server.accept()
        print('连入了一个客户端!')
        clients.append(client)
    except BlockingIOError:

        #已经关闭的客户端
        close_c = []
        #将要回复的客户端以及数据
        msg_ls = []
        #接受数据循环
        for c in clients:
            try:
                data = c.recv(1024)
                if not data:
                    c.close()
                    close_c.append(c)
                #不能直接发,因为操作系统缓存满了会抛出异常
                msg_ls.append((c,data))
            except BlockingIOError:
                pass
            except ConnectionResetError:
                c.close()
                close_c.append(c)

        #发送数据的循环
        #保存已发送的客户端和数据
        rm_msg = []
        for client_and_data in msg_ls:
            client = client_and_data[0]
            data = client_and_data[1]
            try:
                client.send(data.upper())
                #加入删除列表
                rm_msg.append(client_and_data)
            except BlockingIOError:
                pass
        
        #从将要回复的客户端和数据列表删除已经发送的成功客户端和数据
        for i in rm_msg:
            msg_ls.remove(i)
        #清空已经发送完成的客户端和数据列表
        rm_msg.clear()
        
        #从连入的客户端列表删除已经关闭的客户端列表
        for c in close_c:
            clients.remove(c)
        #清空已经关闭的客户端列表
        close_c.clear()

非阻塞IO客户端

import socket
import os,time
client = socket.socket()
client.connect(('192.168.1.67',4396))
while True:
    msg = 'hello i am:%s'%os.getpid()
    time.sleep(1)
    if not msg:
        continue
    client.send(msg.encode('utf-8'))
    data = client.recv(1024)
    print(data.decode('utf-8'))

3.多路复用

非阻塞IO对CPU占有率太高,为了解决这一问题我们使用多路复用

什么是多路复用?

多个连接复用一个线程 反过来说就是一个线程处理多个连接 提高了单线程的处理能力

多路复用提高的是单线程处理网络IO的效率

协程提升的是单线程处理所有IO的效率

 

多路复用服务器:

import socket,select
server = socket.socket()
server.bind(('192.168.1.67',4396))
server.listen()
#select 是帮我们监控连接
#需要给他传两个参数列表,一个检测是否可读(是否可以执行recv),一个检测是否可写(是否执行send)
rlist = [server,]
wlist = []
#默认select是阻塞的.直到其中有一个或几个需要被处理
#存储要发送的数据
msg = {}

#返回值:
#1.可读的连接(可以执行recv)
#2.可写的连接(可以执行send)
while True:
    readable_list,writeable_list,_ = select.select(rlist,wlist,[])
    #接下来处理可读可写的列表

    #处理可读的列表
    for c in readable_list:
        if c == server:#说明当要被处理的是服务器
            client,addr = server.accept()
            #把客户端交给select来检测是否可读
            rlist.append(client)
        else:
            print('客户端可以recv了!')
            data = c.recv(1024)
            print(data.decode('utf-8'))
            #将客户端也交给select来检测是否可写
            wlist.append(c)
            msg[c] = data

    #处理可写列表
    for w in writeable_list:
        w.send(msg[w].upper())
        #将已经发送完成的连接从检测列表删除
        wlist.remove(w)

多路复用客户端:

import socket,os,time
client = socket.socket()
client.connect(('192.168.1.67',4396))
while True:
    msg = 'hello i am:%s'%os.getpid()
    time.sleep(1)
    if not msg:
        continue
    client.send(msg.encode('utf-8'))
    print(client.recv(1024).decode('utf-8'))

4.异步IO

原文地址:https://www.cnblogs.com/lizeqian1994/p/10265119.html