zoukankan      html  css  js  c++  java
  • 五种IO模型

    IO模型

    模型:解决某个问题的固定套路

    IO:输入输出

    IO问题:当输入数据时CPU需要等待很长一段时间(对于cpu而言),在这时间段CPU处于闲置状态,造成了资源浪费

    IO有很多类型:socket网络IO,内存到内存的copy,等待输入等;网络IO需要等待时间是最长的(重点关注)

    目的:等待IO操作过程中利用CPU做起它事情

    网络IO

    经历的步骤和过程

    操作系统的两种状态:内核态,用户态

    当操作系统需要控制硬件时,必须先转到内核态,然后把数据从操作系统缓冲区转到内存缓冲区 ,从内核态转到用户态

    buffer:缓冲,将数据读入到内存所使用的空间;为了降低IO次数

    cache:缓存,从内存中读取数据,存放数据的空间,为了提高读取效率

    recv accpet 需经历wait -- copy

    send 需经历copy

    阻塞IO模型

    默认情况下,TCP程序就是阻塞IO模型

    多线程,多进程的并发也是阻塞IO模型

    提高效率方式:

    (1)当执行recvaccept会进入wait_data的阶段,进程会主动调出一个block指令,进程进入阻塞状态 ,同时认出CPU的执行权,操作系统将CPU分配给其它任务,从而提高CPU利用效率

    (2)当数据到达时,会从内存将数据copy到应用程序缓冲区,并且socket将唤醒处于自身的等待队列中的所有进程

    非阻塞IO模型

    与阻塞模型相反,在调用recvaccpet时都不会阻塞当前进程

    使用方法

    将原本阻塞的socket设置为非阻塞

    该模型在没有数据到达时,会抛出异常,我们需要捕获异常,然后继续不断的询问系统内核直到数据到达为止,可以看出,该模型会大量占有CPU资源做一些无效循环,效率低于阻塞IO

    多路复用IO模型

    属于事件驱动型模型

    多个socket使用同一套处理逻辑

    对于阻塞或非阻塞模型,增加了一个select来帮我们检测socket的状态,从而避免来我们自己检测socket带来的开销

    在多路复用中,阻塞与非阻塞没有区别,因为select会阻塞直到有数据到了

    多路复用对比非阻塞,多路复用极大的降低CPU占用率

    import socket
    import time
    import select
    s = socket.socket()
    s.bind(("127.0.0.1",1688))
    # 设置为非阻塞 模型
    s.setblocking(True) #在多路复用中  阻塞与非阻塞没有区别 因为select会阻塞直到有数据到达为止
    s.listen()
    
    # 待检测是否可读的列表
    r_list = [s]
    # 待检测是否可写的列表
    w_list = []
    
    # 待发送的数据
    msgs = {}
    
    print("开始检测了")
    while True:
        read_ables, write_ables, _= select.select(r_list,w_list,[])
        print("检测出结果了!")
        # print(read_ables,"可以收数据了")
        # print(write_ables,"可以发数据了")
        # 处理可读 也就是接收数据的
        for obj in read_ables: # 拿出所有可以读数据的socket
            #有可能是服务器 有可能是客户端
            if s == obj: # 服务器
                print("来了一个客户端 要连接")
                client,addr = s.accept()
                r_list.append(client)  # 新的客户端也交给select检测了
                
            else:# 如果是客户端则执行recv 接收数据
                print("客户端发来一个数据")
                try:
                    data = obj.recv(1024)
                    if not data:raise ConnectionResetError
                    print("有个客户端说:",data)
                    # 将要发送数据的socket加入到列表中让select检测
                    w_list.append(obj)
                    # 将要发送的数据已经socket对象丢到容器中
                    if obj in msgs:  # 由于容器是一个列表 所以需要先判断是否已经存在了列表
                        msgs[obj].append(data)
                    else:
                        msgs[obj] = [data]
                except ConnectionResetError:
                    obj.close()
                    r_list.remove(obj)
        # 处理可写的 也就是send发送数据
        for obj in write_ables:
            msg_list = msgs.get(obj)
            if msg_list:
                # 遍历发送所有数据
                for m in msg_list:
                    try:
                        obj.send(m.upper())
                    except ConnectionResetError:
                        obj.close()
                        w_list.remove(obj)
                        break
                # 数据从容器中删除
                msgs.pop(obj)
            # 将这个socket从w_list中删除
            w_list.remove(obj)
    

    PS:多路复用并部完美,因为本质上多个任务之间是串行的,如果某个任务耗时比较长将导致其他任务不能立即执行,多路复用最大的优势是高并发

    异步IO模型

    非阻塞IO不等于异步IO,因为copy的过程是一个同步任务,会卡当前主线程

    而异步IO是发起任务后就可以继续执行其他任务当数据cpy到应用程序缓冲区才会给线程发送信号或执行回调

    信号驱动IO模型

    不常用,原因是socket的信号太多,处理起来非常繁琐

  • 相关阅读:
    SQL复制多表数据
    ie与firefox 关于js 的差别(转载)
    水晶报表函数大全【收藏】
    ArcGIS Engine对象库
    SQL Server死锁总结(转载)
    C#制作鹰眼全过程(带注释)
    大块鸭
    【经典】jQuery使用大全
    TreeView控件失效引发的思考
    根据数据集动态生成TREE
  • 原文地址:https://www.cnblogs.com/einsam/p/11157480.html
Copyright © 2011-2022 走看看