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)

     

     

     

  • 相关阅读:
    Java如何编写自动售票机程序
    install windows service
    redis SERVER INSTALL WINDOWS SERVICE
    上传文件
    This problem will occur when running in 64 bit mode with the 32 bit Oracle client components installed.
    解决Uploadify上传控件加载导致的GET 404 Not Found问题
    OracleServiceORCL服务不见了怎么办
    Access to the temp directory is denied. Identity 'NT AUTHORITYNETWORK SERVICE' under which XmlSerializer is running does not have sufficient permiss
    MSSQL Server 2008 数据库安装失败
    数据库数据导出成XML文件
  • 原文地址:https://www.cnblogs.com/WBaiC1/p/11000594.html
Copyright © 2011-2022 走看看