zoukankan      html  css  js  c++  java
  • day39,IO模型,select

                                                                                                    io模型,select

    IO模型

    模型就是解决某个问题的套路

    IO问题:

    输入输出

    我要一个用户名用来执行登陆操作,问题用户名需要用户输入,输入需要耗时, 如果输入没有完成,后续逻辑无法继续,所以默认的处理方式就是 等

    将当前进程阻塞住,切换至其他进程执行,等到按下回车键,拿到了一个用户名,再唤醒刚才的进程,将状态调整为就绪态

    以上处理方案 就称之为阻塞IO模型

    存在的问题:

    当执行到recv时,如果对象并没有发送数据,程序阻塞了,无法执行其他任务

    解决方案:

    多线程或多进程,

          当客户端并发量非常大的时候,服务器可能就无法开启新的线程或进程,如果不对数量加以限制 服务器就崩溃了

    线程池或进程池

          首先限制了数量 保证服务器正常运行,但是问题是,如果客户端都处于阻塞状态,这些线程也阻塞了

    协程:

          使用一个线程处理所有客户端,当一个客户端处于阻塞状态时可以切换至其他客户端任务

    使用非阻塞:

          阻塞IO模型在执行recv 和 accept 时 都需要经历wait_data

         非阻塞IO即 在执行recv 和accept时 不会阻塞 可以继续往下执行

    如何使用:

    将server的blocking设置为False 即设置非阻塞

    存在的问题 :

    这样一来 你的进程 效率 非常高 没有任何的阻塞

    很多情况下 并没有数据需要处理,但是我们的进程也需要不停的询问操作系统 会导致CPU占用过高

    而且是无意义的占用

    案例:

    import socket
    import time
    server = socket.socket()
    server.bind(("127.0.0.1",1688))
    
    server.listen()
    
    server.setblocking(False)
    
    #客户端储存数据的list
    clients = []
    #发送数据的list
    send_data = []
    while True:
        try:
            client, addr = server.accept()
            clients.append(client)
        except BlockingIOError as e :
            time.sleep(0.2)
            #获取到每一个客户端的对象 c 就是每一个客户端的对象
            for c in clients[:]:
                try:
                    # 通过客户端的对象,收发数据,获取到客户端发过来的数据
                    data = c.recv(1024)
                    # 判断客户端发过来的数据是否为空 (收空操作)
                    if not data:
                        c.close()
                        clients.remove(c)
                        # continue
                    # 这里是当客户端发送数据到缓存的时候,刚好到缓存的最大值, 
                    # 那么数据就有可能丢失 ,所以就需要try和数据进行处理
                    # c.send(data.upper())
                    send_data.append((c, data))
                except BlockingIOError as e:
                    print("这个客户端还不需要处理")
                except ConnectionResetError as e:
                    print(e)
                    c.close()
                    clients.remove(c)
            #发送数据到客户端
            for i in send_data[:]:
                try:
                    c, msg = i
                    # 发送数据
                    c.send(msg.upper())
                    send_data.remove(i)
                except BlockingIOError:
                    pass

    多路复用IO模型

    案例:

    # 因为使用使用socket中的非阻塞,太占用CPU ,需要通过不断的询问,这样就是一个死循环
    # 所以就使用select这个类来弥补这个问题
    import socket
    import select
    server = socket.socket()
    server.bind(("127.0.0.1", 1688))
    server.listen()
    
    '''
     在select中需要注意的几个个参数是
      rlist 可读的列表
      wlist, 可写的列表
      xlist, 错误信息的列表 
      timeout 这个是询问时间,如果这个时间超过多少就会停止询问
    '''
    rlist = [server,]
    wlist = []
    msgs = []
    while True:
        #返回的是可读和可写的列表,这里会阻塞到一个或者多个socket可以被处理
        read_rlist,write_wlist,_ = select.select(rlist,wlist,[])
        for soc in read_rlist:
            if soc == server:
                #这里需要注意的是需要判断这个可读的列表中存放的是socket还是客户端的对象
                client,addr = soc.accept()
                #对客户端进行处理
                rlist.append(client)
            else:
                #对客户端的数据进行处理
                try:
                    data = soc.recv(1024)
                    if not data:
                        soc.close()
                        rlist.remove(soc)
                        continue
                    if soc not in wlist:
                        wlist.append(soc)
                    msgs.append((soc,data))
                except ConnectionResetError as e:
                    soc.close()
                    rlist.remove(soc)
                    #如果wlist中还有请求对象就删除这个对象
                    if soc in wlist:
                        wlist.remove(soc)
        #发送数据到客服端
        for soc in write_wlist:
            for i in msgs[:]:
                if i[0] == soc:
                    soc.send(i[1])
                    msgs.remove(i)
            wlist.remove(soc)

     

     

     

  • 相关阅读:
    Consul注销实例
    sql优化基础篇
    linux下执行java类(运行java定时器)
    ExecutorService 的理解与使用
    精度计算的方法
    内部类详解
    接口的作用
    面向对象之继承和组合浅谈
    构造器前篇
    教师编制考试数据分析
  • 原文地址:https://www.cnblogs.com/WBaiC1/p/11000594.html
Copyright © 2011-2022 走看看