Python 之IO模型

阻塞IO模型:以前写的套接字通信都是阻塞型的。通过并发提高效率

非阻塞IO模型:

from socket import *

# 并不推荐使用,一是消耗cpu资源,二是会响应延迟
server = socket(AF_INET, SOCK_STREAM)
server.bind(('127.0.0.1',8087))
server.listen(5)
server.setblocking(False)
conn_list = []
wlist = []
while True:   # 死循环,消耗cpu大
    try:
        conn,addr = server.accept() #等待连接
        conn_list.append(conn)
        print(conn_list)
    except BlockingIOError:   # 如果没有客户端发送连接请求,干通信活
        del_list=[]
        # 收消息
        for conn in conn_list:  # 如果有超多客户端时,可能会服务延迟
            try:
                data = conn.recv(1024)
                if not data:
                    del_list.append(conn)
                    continue
                wlist.append((conn,data.upper()))
            except BlockingIOError:
                continue
            except Exception:
                conn.close()
                del_list.append(conn)
        #发消息
        del_wlist = []
        for item in wlist:
            try:
                conn = item[0]
                data = item[1]
                conn.send(data)
                del_list.append(item)
            except BlockingIOError:
                pass
        for item in del_wlist:
            wlist.remove(item)
        for conn in del_list:
            conn_list.remove(conn)
server.close()

多路复用IO模型,又叫事件驱动IO,使用select模块或poll(epoll)实现。

select模块优点:只用单线程(进程)执行,占用资源少,同时能为多客户端提供服务。

缺点:select()接口并不是实现‘事件驱动’的最好选择,因为当套接字较多时,需要消耗大量时间去轮询。很多操作系统提供了更为高效的接口,如

linux提供了epoll,BSD提供了kqueue,Solaris提供了/dev/poll。。。

epoll更被推荐(采用异步方式,有回调机制,不需轮询),遗憾的是各操作系统提供的epoll接口差异很大。

selector模块能根据平台选择IO多路复用的不同机制

import socket
import select
server = socket.socket()
server.bind(('127.0.0.1', 8800))
server.listen(5)
# sock.setblocking(False)
rlist = [server, ]  # 有新客户端连接时,sock变化
wlist = []
wdata = {}
while 1:
    rl, wl, el=select.select(rlist, wlist, [], 0.5) # 每过0.5s监听有变化的套接字(server或conn)
    print('rl', rl)
    print('wl', wl)
    for sock in rl:
        if sock == server:
            conn,addr = sock.accept() # 客户端发消息时,conn变化
            rlist.append(conn)  # 有变化的conn加入rlist
            print('server working...')
        else:
            try:
                data = sock.recv(1024)
                # linux上
                if not data:
                    sock.close()
                    rlist.remove(sock)
                    continue
                wlist.append(sock)
                wdata[sock]=data.upper()
            except Exception:
                sock.close()
                rlist.remove(sock)
    for sock in wl:
        data = wdata[sock]
        sock.send(data)
        wlist.remove(sock)
        wdata.pop(sock)

异步IO模型

原文地址:https://www.cnblogs.com/stin/p/8549811.html