zoukankan      html  css  js  c++  java
  • IO多路复用

    在前一篇文章中,我们实现了通过非阻塞套接字的并发服务,但是这种实现方式是有很多问题的。

    一、CPU资源的极大浪费;

    二、如果没有连接那么,accept()和recv()都在做无用功;

    三、对BlockIOError的处理也是在做无用功。

    针对以上问题,现在我们使用IO多路复用的技术来实现并发的服务。

    什么是IO多路复用

    IO多路复用是指内核一旦发现进程指定的一个或者多个IO条件准备读取,它就通知该进程。IO多路复用适用如下场合:

    1.当客户需要处理多个描述符时,必须使用I/O复用。
    
    2.当一个客户同时处理多个套接口时,而这种情况是可能的,但很少出现。
    
    3.如果一个TCP服务器既要处理监听套接口,又要处理已连接套接口。
    
    4.如果一个服务器即要处理TCP,又要处理UDP。
    
    5.如果一个服务器要处理多个服务或多个协议
    目前支持I/O多路复用的系统调用有 select,pselect,poll,epoll但select,pselect,poll,epoll本质上都是同步I/O。其中epoll时Linux系统独有的。也是要主要介绍的。

    select

    Python的select()方法直接调用操作系统的IO接口,它监控sockets,open files, and pipes(所有带fileno()方法的文件句柄)何时变成readable 和writeable, 或者通信错误,select()使得同时监控多个连接变的简单,并且这比写一个长循环来等待和监控多客户端连接要高效,因为select直接通过操作系统提供的C的网络接口进行操作,而不是通过Python的解释器。

    select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点。select的一 个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,可以通过修改宏定义甚至重新编译内核的方式提升这一限制,但是这样会造成效率的降低

    select(rlist, wlist, xlist, timeout=None)

    select()方法接收并监控3个通信列表, 第一个rlist监控所有要进来的输入数据,第二个wlist是监控所有要发出去的输出数据,第三个监控异常错误数据,第四个设置指定等待时间,如果想立即返回,设为null即可,最后需要创建2个列表来包含输入和输出信息来传给select(),让select方法通过内核去监控,然后生成三个实例。zaipython中直接导入select使用。

    epoll

    epoll的方式,这种效率更高,但是这种方式在Windows下不支持,在Linux是支持的,selectors模块就是默认使用就是epoll,但是如果在windows系统上使用selectors模块,就会找不到epoll,从而使用select。

    服务端代码:

    import socket
    import selectors
    server=socket.socket()
    server.bind(('0.0.0.0',8899))
    server.listen()
    epoll=selectors.DefaultSelector()
    def recv_func(conn):
        data=conn.recv(1024)
        if data==b'':
            epoll.unregister(conn)
            conn.close()
        else:
            print("接收到数据:>>>",data)
            conn.send(data)
    def server_func(ser):
        conn,addr=ser.accept()
        print("连接处理!")
        epoll.register(conn,selectors.EVENT_READ,recv_func)
    epoll.register(server,selectors.EVENT_READ,server_func)
    while True:
        events=epoll.select()
        for key,value in events:
            callback=key.data
            sock=key.fileobj
            callback(sock)

    客户端代码

    import socket
    client=socket.socket()
    client.connect(('127.0.0.1',8899))
    while True:
        data=input("请输入传送的数据:>>>>")
        client.send(data.encode())
        print("接收到的数据:>>>",client.recv(1024).decode())
     
  • 相关阅读:
    三元运算,列表解析,生成器表达式
    迭代器补充
    迭代器协议和for循环工作机制
    文件seek方法的补充
    文件操作的其他方法
    文件操作b模式
    文件操作的其他模式
    其他内置函数
    [TimLinux] JavaScript table的td内容超过宽度缩为三个点
    [TimLinux] JavaScript BOM浏览器对象模型
  • 原文地址:https://www.cnblogs.com/austinjoe/p/9661502.html
Copyright © 2011-2022 走看看