zoukankan      html  css  js  c++  java
  • 并发编程(三) IO模型

    五 IO模型

    常用的IO模型有4种:

    • 阻塞IO
    • 非阻塞IO
    • IO多路复用
    • 异步IO

    不常用的有:

    • 驱动信号

    5.1 阻塞IO、非阻塞IO

    • 阻塞IO:进程不能做其他的事情
    • 非阻塞IO:等待数据无阻塞

    阻塞IO

    阻塞IO就是全程阻塞,其中,全程指的是等待数据和 数据从内核态拷贝到用户态。

    全程阻塞就是以上两个步骤都阻塞。如图:

    系统调用两个阶段:

    • wait for data:阻塞
    • copy data:阻塞

    非阻塞IO

    非阻塞IO是部分阻塞,
    等待数据时不会阻塞,而是在固定时间内循环发起系统调用,请求不到做自己的事情,等待下次请求,
    而数据从内核态拷贝到用户态还是阻塞的。如图:

    系统调用两个阶段:

    • wait for data:非阻塞
    • copy data:阻塞

    优点:
    等待数据无阻塞

    缺点:
    1.系统调用发送太多
    2.数据不是即时接收的

    ps:socket设置socket对象.setblocking(False) 设置阻塞状态为非阻塞

    5.2 IO多路复用

    IO多路复用:全程阻塞,监听多个链接

    系统调用两个阶段:

    • wait for data:阻塞
    • copy data:阻塞

    实现IO多路复用的常用方式有:

    • select
    • poll
    • epoll

    原理

    基本原理:
    通过select/poll/epoll函数不断轮询所负责的所有socket套接字,当某个socket套接字有数据到达,就通知用户进程。

    特点:
    就是单个process可以同时处理多个网络连接的IO,

    ps:不同的操作系统提供的函数不同:
    windows系统: select
    linux系统: select、poll、epoll

    select模块

    系统调用通过select模块完成wait for data的工作

    示例:
    select监听多个socket对象(sock是socket对象),实现并发

    r, w, e = select.select([sock,], [], [])  # 等待链接 
    for obj in r:
    	conn, addr = obj.accept()
    

    示例升级:

    inputs = [sock,] 
    r, w, e = select.select(inputs, [], [])  # inputs监听有变化的套接字 inputs=[sock,conn1,conn2,...]
    for obj in r:  # 第一次[sock,] 第二次[conn1,]
    	if obj == sock:  # 如果返回的r = sock,说明有连接请求
    		conn, addr = obj.accept()
    		inputs.append(conn)  # inputs=[sock, conn1, conn2]
    	else:  # 否则,可以接收数据了
    		data = obj.recv(1024)
    

    ps:关于文件描述符的tips(socket套接字)

    1.每一个套接字对象的本质就是一个非零整数,不会变(fb=4)

    <socket.socket fd=4, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, 
    proto=0, laddr=('127.0.0.1', 8080), raddr=('127.0.0.1', 51963)>
    

    2.收发数据的时候,对于接收端而言,数据先到内核空间,然后copy到用户空间,同时内核空间的数据被清空

    3.根据TCP协议,当发送端接收到接收端的确认信息后,清空内核空间的数据,否则不清空

    select、poll、epoll

    select:

    • 每次调用select都要将所有的fd(文件描述符),copy到你的内核空间
    • 遍历所有的fd,是否有数据访问
    • 最大连接数(1024),超出链接不再监听

    ps:select的特点也是其缺点,会导致效率下降:

    poll:

    • 每次调用select都要将所有的fd(文件描述符),copy到你的内核空间
    • 遍历所有的fd,是否有数据访问
    • 最大连接数没有限制

    epoll:

    • 不同于select和poll只有一个函数,epoll通过三个函数实现实现轮询socket:
      • 第一个函数:创建epoll句柄:将所有的fd(文件描述符),copy到你的内核空间,只copy一次
      • 回调函数:为所有fd绑定一个回调函数,一旦有数据访问,触发回调函数,回调函数将fd放入一个链表中
      • 第三个函数:判断链表是否为空
    • epoll最大连接数没有上线

    ps:回调函数
    某一个函数或者某一个动作,成功完成之后,会触发的函数

    selectors模块

    selectors是select的升级版

    selectors基于select模块实现IO多路复用,调用语句selectors.DefaultSelector()创建selecters对象,特点是根据平台自动选择最佳IO多路复用机制,调用顺序:epoll > poll > select

    import selectors
    import socket
    
    sel = selectors.DefaultSelector()  # 根据平台自动选择最佳IO多路复用机制
    
    def accept(sock, mask):
        conn, addr = sock.accept()
        sel.register(conn, selectors.EVENT_READ, read)  # 将conn和read()注册到一起,当conn有变化时执行read()
    
    def read(conn, mask):
        try:
            data = conn.recv(1000)
            print(data.decode('utf8'))
            inputs = input('>>:').strip()
            conn.send(inputs.encode('utf8'))
        except Exception:
            sel.unregister(conn)
            conn.close()
    
    sock = socket.socket()
    sock.bind(('127.0.0.1', 8080))
    sock.listen(100)
    sock.setblocking(False)  # 设置为非阻塞IO
    
    sel.register(sock, selectors.EVENT_READ, accept)  # 将sock和accept()注册到一起,当sock有变化时执行accept()
    
    while True:
        events = sel.select()  # 监听  [(key1,mask1),(key2),(mask2)]
        for key, mask in events:
            func = key.data  # 1 key.data就是accept   # 2 key.data就是read
            obj = key.fileobj  # 1 key.fileobj就是sock   # 2 key.fileobj就是conn
    
            func(obj, mask)  # 1 accept(sock,mask)   # 2read(conn,mask)
        
    

    5.3 同步IO、异步IO

    同步IO

    只要系统调用中存在阻塞就是同步IO,
    所以,阻塞IO、非阻塞IO、IO多路复用都是同步IO

    异步IO

    全程无阻塞,实现复杂

    系统调用两个阶段:

    • wait for data:非阻塞
    • copy data:非阻塞
  • 相关阅读:
    subprocess模块讲解
    正则
    logging日志模块
    2-30hashlib模块讲解
    json pickle复习 shelve模块讲解
    XML、PyYAML和configparser模块讲解
    os模块
    2-25sys模块和shutil模块讲解
    随机生成模块
    时间模块
  • 原文地址:https://www.cnblogs.com/sunqim16/p/6835896.html
Copyright © 2011-2022 走看看