38 并发编程5 - IO模型

并发编程 - IO模型

1 IO模型简介

前提,这里介绍的IO模型针对的是网络IO。

1.1 五种IO模型
IO模型IO Model
阻塞IOBlocking IO
非阻塞IONonblocking IO
IO多路复用IO Multiplexing
信号驱动IOSigal Driven IO
异步IOAsychronous IO
1.2 网络通信过程简介

copy data阶段
发送数据:程序将待发送的数据进行拷贝并交给操作系统。
接收数据:操作系统将待接收的数据进行拷贝并交给指定的程序。

这里以接收方为例。
阶段1 等待数据准备
接收方一直等待发送方发送数据
阶段2 将数据从内核拷贝到进程中
接收方收到数据后将数据经由操作系统拷贝给指定的程序(copy data阶段)

1.3 常见的网络阻塞状态

accept
recv/recvfrom
上面两个动作属于被动执行,即是否执行由对方决定,如果对方发送连接请求/数据,则执行accept/recv/recvfrom,否则一直处于等待状态。

send也属于IO操作,但属于主动触发,即发送数据的动作由自己决定,因此造成阻塞的时间非常短,不在这里讨论由send引发的阻塞。

2 阻塞IO模型

在这里插入图片描述

  1. 程序使用recv(TCP) / recvfrom(UDP) 发送系统调用,向内核(操作系统)索要数据,操作系统等待对方发送数据;
  2. 操作系统收到数据后,将数据进行拷贝给程序。

上面两个阶段执行结束后程序才能继续执行。

3 非阻塞IO模型

在这里插入图片描述
程序每次向操作系统发送系统调用后,都会立即得到响应,无论是否存在数据,这意味着程序发送系统调用后不会等待,可以立即处理其它事情。
非阻塞IO模型将阻塞IO模型中的所有阻塞操作变成非阻塞操作,程序一直处于就绪态和运行态,因此程序可以尽可能地占用CPU的资源。

import socket

server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)

# 将所有的网络阻塞变为非阻塞 (accept, recv)
# 这样做在没有对方回应时,accept, recv会抛出BlockingIOError异常。
server.setblocking(False)

r_list = []
del_list = []
while True:
    try:
        # 判断是否收到新的连接请求
        # 没有则抛出异常
        conn, addr = server.accept()
        r_list.append(conn)
    except BlockingIOError:
        # 说明目前没有新的客户端连接请求
        # 检查已连接的客户端是否发送数据
        for conn in r_list:
            try:
                # 判断是否接收到来自客户端的数据
                # 没有则抛出异常
                data = conn.recv(1024)

                # 说明客户端断开了连接(Linux)
                if len(data) == 0:
                    conn.close()
                    del_list.append(conn)
                    continue

                data = data.decode('utf-8')
                conn.send(data.upper().encode('utf-8'))
            except BlockingIOError:
                # 说明这个客户端连接没有发送数据,判断下一个
                continue
            except ConnectionResetError:
                # 说明客户端断开了连接(Windows)
                conn.close()
                del_list.append(conn)

        # 回收失效的连接
        for conn in del_list:
            r_list.remove(conn)
        del_list.clear()

总结:
非阻塞IO模型会导致程序长时间占用CPU却不做任何实际的任务,因此该模型非常消耗和浪费CPU资源,实际应用中不会考虑使用非阻塞IO模型。

4 IO多路复用模型

在这里插入图片描述
操作系统提供监管机制,用来监听socket对象和conn对象,当对象被触发时立即返回对应的对象。

当监管的对象只有一个时,IO多路复用模型的效率低于阻塞IO模型的效率,但是IO多路复用模型可以一次性监管大量的对象。

注意,这个监管机制是操作系统提供的。

import socket
import select

server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)

server.setblocking(False)

read_list = [server]
while True:
    # rlist, wlist, xlist
    r_list, w_list, x_list = select.select(read_list, [], [])
    # 监测server对象
    # 当收到客户端的连接请求后,建立socket对象(server)。
    # socket对象建立完毕后处于可读的状态,操作系统会将socket对象返回。

    for each_obj in r_list:
        # r_list存在socket对象和处理连接请求后添加的conn对象
        # 需要判断不同类型的对象
        if each_obj is server:
            conn, addr = each_obj.accept()
            read_list.append(conn)
        else:
            try:
                data = each_obj.recv(1024)
                if len(data) == 0:
                    each_obj.close()
                    read_list.remove(each_obj)
                    continue

                data = data.decode('utf-8')
                print(data)
                each_obj.send(data.upper().encode('utf-8'))
            except ConnectionResetError:
                each_obj.close()
                read_list.remove(each_obj)

监管机制汇总

  1. select机制
    windows和Linux
  2. poll机制
    Linux
    poll机制监管的总量比select机制监管的总量多。
    当需要监管的对象非常多时,poll机制和select机制可能出现非常大的延时响应。
  3. epoll机制
    Linux
    为每一个监管对象绑定了一个回调机制,一旦出现响应,可以通过回调机制立即处理。

5 异步IO模型

在这里插入图片描述
程序发送系统调用后不会等待,立即去处理其它事情。
操作系统处理完数据后会向程序发送信号,程序收到信号后停下正在进行的任务,去接收并处理操作系统发送的数据。

异步IO模型可以在单线程下实现并发的效果。
异步IO模型是所有模型中效率最高,也是使用最广泛的。

模块:asyncio
支持异步的框架:sanic, tronado, twisted
支持异步的框架的特点是运行速度非常快。

import asyncio
import threading


@asyncio.coroutine
def print_hello():
    print(f'Hello. {threading.current_thread()}')
    yield from asyncio.sleep(1)  # 模拟IO操作
    print(f'Hello. {threading.current_thread()}')


loop = asyncio.get_event_loop()
task_list = [print_hello(), print_hello()]
loop.run_until_complete(asyncio.wait(task_list))
loop.close()

6 IO模型总结

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值