线程 四

2021-04-08  本文已影响0人  吃可爱长大鸭

目录

1.内容
2.多路复用
3.非阻塞IO

1.内容

IO 模型
    什么是IO 指的是输入输出,其执行速度都非常慢
    模型,指固定的套路
    IO模型 就是 所有可以实现输入输出的套路

IO的分类
    1.本地IO 指的是输入输出到本地计算机 比如写入硬盘
    2.网络IO 指的是输入输出到 网络中的计算机 速度远比本地IO慢(*****)

网络IO的输入输出过程


IO模型(******):
    1.阻塞型IO
        之前学习的IO操作处理gevent都是阻塞型的
        1.可以利用多线程来提高效率
          线程数量不能太多 会造成内存溢出
        2.线程池可以解决线程太多的问题
          但是如果线程池数量达到最大  其他客户端将进入等待

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

    2.非阻塞IO

    3.多路复用
    4.异步IO

2.多路复用

多路复用

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

多路复用提升的 单线程处理网络IO的效率
协程提升的是 单线程处理所有IO的效率

######client
import socket
import os
import time
c = socket.socket()
c.connect(("127.0.0.1",21211))

while True:
    msg = "hello i am: %s" % os.getpid()
    time.sleep(1)
    if not msg:
        continue
    c.send(msg.encode("utf-8"))
    print(c.recv(1024).decode("utf-8"))

####server
import socket
import select
server = socket.socket()
server.bind(("127.0.0.1",21211))
server.listen()
# server.setblocking(False)

# select 是帮我们监控连接
# 需要给它传两个列表 一个是检测是否可读(是否可以执行recv)  一个是检测是否可写(是否可执行send)
rlist = [server,]
wlist = []

# 存储要发送的数据
msg = {}

# 默认select是阻塞的 会直到有其中一个或几个需要被处理
# 返回值
#    1.可读的连接(可以执行recv)
#    2.可写的连接(可以执行send)
while True:
    readable_list,writeable_list,_ = select.select(rlist,wlist,[])
    # 接下来就是要处理这些可读可写列表
    print(readable_list)
    # 处理可读列表
    for c in readable_list:
        if c == server: # 说明当需要被处理的是服务器
            client,addr = c.accept()
            # 把客户端也交给select来检测
            rlist.append(client)
        else:
            print("客户端可以recv啦!")
            data = c.recv(1024)
            print(data.decode("utf-8"))
            # 给客户端返回数据
            # c.send(data.upper())
            wlist.append(c)   # 将客户端也交给select检测是否可写
            msg[c] = data

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

3.非阻塞IO

####client
import socket
import os,time
c = socket.socket()
c.connect(("127.0.0.1",21211))

while True:
    msg = "hello i am: %s" % os.getpid()
    time.sleep(1)
    if not msg:

        continue
    c.send(msg.encode("utf-8"))
    print(c.recv(1024).decode("utf-8"))

####server
import  socket,time

from time import sleep
server = socket.socket()
server.bind(("127.0.0.1",21211))
server.listen()

server.setblocking(False)
# 保存所有的客户端
clients = []

# 需要发送的数据
msg_ls = []

while True:
    # 需要接收三次握手数据  所以也是一个阻塞 必须经历wait 和 copy
    try:
        client,addr = server.accept()
        print("来了一个客户端....")
        # 每次执行到这个代码的时候 client的值都是一个新的值 则意味只能处理本次的新的客户端
        # while True:
        #     client.send(client.recv(1024).upper())
        clients.append(client)
    except BlockingIOError:
        # sleep(0.1) #
        print("还没有数据可以处理 那就干别的事情去")
        # 执行except 说明服务器没有请求可以处理  可以去处理客户端通讯
        # 已经关闭的 需要删除的客户端
        close_ls = []
        # 接收数据的循环
        for c in clients:
            try:
                data = c.recv(1024)
                if not data:
                    c.close()
                    close_ls.append(c)
                    continue
                # 不能直接发 因为操作系统缓存如果满了 会抛异常
                # c.send(data.upper())
                msg_ls.append((c,data))
            except BlockingIOError:
                pass
            except ConnectionResetError:
                c.close()
                close_ls.append(c)
        # 遍历完成后 删除关闭的连接
        for i in close_ls:
            clients.remove(i)
        close_ls.clear()

        
        # 发送数据的循环
        # 保存已经发送过的数据
        rm_msg = []
        for i in msg_ls:
            try:
                i[0].send(i[1].upper())
                rm_msg.append(i)
                print("发送成功!")

            except BlockingIOError:
                print("发送失败!")

        # 清理已经发送过的数据!
        for msg in rm_msg:
            msg_ls.remove(msg)

        rm_msg.clear()

####server2
import socket
server = socket.socket()
server.bind(("127.0.0.1",21211))
server.listen()

server.setblocking(False)


# all clients
clients = []

while True:
    try:
        client,addr = server.accept()
        clients.append(client)
    except BlockingIOError:

        # 存储所有已经关闭的客户端
        close_ls = []

        # 存储所有需要发送数据的客户端和数据
        msg_ls = []
        for c in  clients:
            try:
                data = c.recv(1024)
                if not data:
                    c.close()
                    close_ls.append(c)
                # 把要发送数据的 客户端 和数据存储到列表中  单独发送
                msg_ls.append((c,data))
            except BlockingIOError:
                pass
            except ConnectionResetError:
                c.close()
                close_ls.append(c)

        # 处理发送数据
        # 已经发送完成的客户端和数据
        sended_msg = []
        for client_and_data in msg_ls:
            c = client_and_data[0]
            data= client_and_data[1]
            try:
                c.send(data.upper())
                # 加入待删除列表
                sended_msg.append(client_and_data)
            except BlockingIOError:
                pass

        # 将已经发送成功的数据从待发送列表中删除
        for i in sended_msg:
            msg_ls.remove(i)
        sended_msg.clear()


        # 把已经关闭的连接从 所有客户端列表中删除
        for i in close_ls:
            clients.remove(i)
        close_ls.clear()

上一篇 下一篇

猜你喜欢

热点阅读