• io模型


    一.先讲一个形象比喻五种io模型

    1.阻塞I/O模型

    老李去火车站买票,排队三天买到一张退票。

    耗费:在火车站吃喝拉撒3天,其他事一件没干。

    2.非阻塞I/O模型

    老李去火车站买票,隔12小时去火车站文有没有退票,三天后买到一张票。

    耗费:往返车站6次,路上6小时,其他时间做了好多事。

    3.I/O

    1)select/poll

    老李去火车站买票,委托黄牛,(select黄牛一次只能帮1024个人买票,poll黄牛无上限)然后每隔离6小时打电话黄牛询问,黄牛三天内买到票,然后老李去火车站交钱领票。

    耗费:往返车站2次,路上2小时,黄牛手续费100,打电话17次

    2)epoll

    老李去火车站买票,委托黄牛,黄牛买到后即通知老李去领,然后老李去火车站交钱领票。

    耗费:往返车站两次,路上2小时,黄牛手续费100元,无需打电话。

    4)信号驱动I/O模型

    老李去火车站买票,给售票员留下电话,有票后,售票员电话通知老李,然后老李去火车站交钱领票。

    耗费:往返车站2次,路上2小时,免费黄牛100元,无需打电话。

    5)异步I/O模型

    老李去火车站买票,给售票员留下电话,有票后,售票员电话通知老李并快递送票上门。

    耗费:往返车站1次,路上一小时,免黄牛费100,无需打电话。

    二.waitdata 和 copydata

    1)等待数据准备 (Waiting for the data to be ready)
    2)将数据从内核拷贝到进程中(Copying the data from the kernel to the process)

     记住这两点很重要,因为这些IO模型的区别就是在两个阶段上各有不同的情况。

        补充

    #1、输入操作:read、readv、recv、recvfrom、recvmsg共5个函数,如果会阻塞状态,则会经理wait data和copy data两个阶段,如果设置为非阻塞则在wait 不到data时抛出异常
    
    #2、输出操作:write、writev、send、sendto、sendmsg共5个函数,在发送缓存区满了会阻塞在原地,如果设置为非阻塞,则会抛出异常
    
    #3、接收外来链接:accept,与输入操作类似
    
    #4、发起外出链接:connect,与输出操作类似


    三.阻塞IO模型

    #服务端
    from concurrent.futures import ThreadPoolExecutor
    import socket
    
    server = socket.socket()
    #重用端口
    server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    
    server.bind(("127.0.0.1",9999))
    
    server.listen(5)
    
    #线程池
    pool=ThreadPoolExecutor(3)
    
    def data_handler(conn):
        print("一个新连接...")
        while True:
            data = conn.recv(1024)
            conn.send(data.upper())
    
    while True:
        conn,addr = server.accept()
        #切到处理数据的任务去执行
        pool.submit(data_handler,conn)
    
    #客户端
    import socket
    c = socket.socket()
    
    c.connect(("127.0.0.1",9999))
    
    while True:
        msg = input(">>>:")
        if not msg:continue
        c.send(msg.encode("utf-8"))
        data = c.recv(1024)
        print(data.decode("utf-8"))

    四.非阻塞IO模型

        在非阻塞IO中 需要不断循环询问操作是否有需要处理的数据

        这一来 对应程序而言 效率确实高

        但是操作系统而言 你的程序就像一个病毒 CPU江被你强行霸占

        当你的TCP程序 没有锁 没有数据接收 没有数据发送时 就是在做无用循环 浪费系统资源

    #服务器
    from concurrent.futures import ThreadPoolExecutor
    import socket
    
    server = socket.socket()
    #重用端口
    server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    
    server.bind(("192.168.11.96",9998))
    
    server.listen(5)
    
    #设置是否为阻塞 默认阻塞
    server.setblocking(False)
    
    def data_handler(conn):
        print("一个新连接..")
        while True:
            data = conn.recv(1024)
            conn.send(data.upper())
    #已经连接的客户端
    clients = []
    # 需要发送的数据
    send_datas=[]
    #已经发送完的 需要删除的数据
    del_datas = []
    # 待关闭的客户端
    closed_cs = []
    import time
    while True:
        try:
            conn,addr = server.accept()
            #切到处理数据的任务去执行
            #代码走到这里才算是连接成功
            #把连接成功的客户端存起来
            clients.append(conn)
        except BlockingIOError:
            # print("没有可以处理的连接 就干别的活儿")
            #要处理的是已经连接成功的客户端
            # 接受数据
            for c in clients:
                try:
                    data = c.recv(1024)
                    if not data:
                        #对方关闭了连接
                        c.close()
                        #从客户端列表中删除它
                        closed_cs.append(c)
                        continue
                    print("收到%s"%data.decode("utf-8"))
                    #现在非阻塞 send直接往缓存塞 如果缓存满了 肯定有错误 需要单独处理
                    #c.send(data.upper())
                    send_datas.append((c,data))
                except BlockingIOError:
                    pass
                except ConnectionRefusedError:
                    # 对方关闭了连接
                    c.close()
                    #从客户端iebook中删除它
                    closed_cs.append(c)
            #处理发送数据
            for data in send_datas:
                try:
                    data[0].send(data[1].upper())
                    #发送成功需要删除 不能直接删除
                    # send_datas.remove(data)
                    del_datas.append(data)
                except BlockingIOError:
                    continue
                except ConnectionRefusedError:
                    # 客户端连接需要删除
                    data[0].close()
                    closed_cs.append(data[0])
                    #等待发送的数据需要删除
                    del_datas.append(data)
                # 删除无用数据
                for d in del_datas:
                    # 从待发送的列表中删除
                    send_datas.remove(d)
                del_datas.clear()
                for c in closed_cs:
                    clients.remove(c)
                closed_cs.clear()
    
    #客户端
    
    from concurrent.futures import ThreadPoolExecutor
    import socket
    
    server = socket.socket()
    #重用端口
    server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    
    server.bind(("192.168.11.96",9998))
    
    server.listen(5)
    
    #设置是否为阻塞 默认阻塞
    server.setblocking(False)
    
    def data_handler(conn):
        print("一个新连接..")
        while True:
            data = conn.recv(1024)
            conn.send(data.upper())
    #已经连接的客户端
    clients = []
    # 需要发送的数据
    send_datas=[]
    #已经发送完的 需要删除的数据
    del_datas = []
    # 待关闭的客户端
    closed_cs = []
    import time
    while True:
        try:
            conn,addr = server.accept()
            #切到处理数据的任务去执行
            #代码走到这里才算是连接成功
            #把连接成功的客户端存起来
            clients.append(conn)
        except BlockingIOError:
            # print("没有可以处理的连接 就干别的活儿")
            #要处理的是已经连接成功的客户端
            # 接受数据
            for c in clients:
                try:
                    data = c.recv(1024)
                    if not data:
                        #对方关闭了连接
                        c.close()
                        #从客户端列表中删除它
                        closed_cs.append(c)
                        continue
                    print("收到%s"%data.decode("utf-8"))
                    #现在非阻塞 send直接往缓存塞 如果缓存满了 肯定有错误 需要单独处理
                    #c.send(data.upper())
                    send_datas.append((c,data))
                except BlockingIOError:
                    pass
                except ConnectionRefusedError:
                    # 对方关闭了连接
                    c.close()
                    #从客户端iebook中删除它
                    closed_cs.append(c)
            #处理发送数据
            for data in send_datas:
                try:
                    data[0].send(data[1].upper())
                    #发送成功需要删除 不能直接删除
                    # send_datas.remove(data)
                    del_datas.append(data)
                except BlockingIOError:
                    continue
                except ConnectionRefusedError:
                    # 客户端连接需要删除
                    data[0].close()
                    closed_cs.append(data[0])
                    #等待发送的数据需要删除
                    del_datas.append(data)
                # 删除无用数据
                for d in del_datas:
                    # 从待发送的列表中删除
                    send_datas.remove(d)
                del_datas.clear()
                for c in closed_cs:
                    clients.remove(c)
                closed_cs.clear()

    五.异步IO模型

    import asyncio
    asyncio.coroutine()
    from concurrent.futures import  ThreadPoolExecutor
    
    def task():
        print("read start")
        with open(r"D:python视频存放目录上海python全栈4期day40多路复用,降低CPU占用服务器.py",encoding="utf-8") as f:
            text = f.read()
            # f.write()
        print("read end")
        return text
    
    
    def fin(f):
        print("fin")
        print(f.result())
    
    
    pool = ThreadPoolExecutor(1)
    future = pool.submit(task)
    future.add_done_callback(fin)
    
    print("主 over")
    # 这种方式看起来像是异步IO 但是对于子线程而言不是
    # 在子线程中 执行read 是阻塞的 以为CPU必须切走 但是不能保证切到当前程序的其他线程
    # 想要的效果就是 在执行read 是不阻塞 还能干其他活   谁能实现  只有协程
    # asyncio 内部是使用的是协程

     六.IO模型比较分析 

  • 相关阅读:
    针对当前用户 对方法加锁
    二叉树
    return与析构续
    return与析构函数
    拷贝构造函数
    引用
    返回引用的函数值和参数的引用
    使用引用返回函数值
    邻接表--图 部分代码
    dec,hex and oct
  • 原文地址:https://www.cnblogs.com/gongcheng-/p/9960478.html
Copyright © 2020-2023  润新知