系列文章目录


文章目录

  • 系列文章目录
  • 一、I/O模型的介绍
  • 二、阻塞I/O模型
  • 三、非阻塞I/O
  • 四、I/O多路复用模型
  • 五、异步I/O模型


一、I/O模型的介绍

本文中的I/O模型仅考虑网络I/O,其他I/O不在考虑范围内。

  • 预备知识点:
    内存分为内核缓冲区和用户缓冲区。网络下载的资源,硬盘加载的资源,先放到内核缓冲区,之后再拷贝到应用程序的缓冲区,应用程序才能用这个数据。
  • 五种I/O模型:
  • blocking I/O —— 阻塞I/O
  • nonblocking I/O —— 非阻塞I/O
  • I/O multiplexing —— I/O多路复用
  • signal driven I/O —— 信号驱动I/O (不常用)
  • asynchronous I/O —— 异步I/O(其他四个也被称为同步I/O)

I/O模型只是一种编程的“套路”,合理的使用,可以提高程序的效率,减少阻塞。

二、阻塞I/O模型

这是最简单的I/O模型,应用程序执行系统调用后,就一直在阻塞,直到收到数据。

python多模态模型搭建 python的模型_IO模型

三、非阻塞I/O

该模型中,用程序发起系统调用,操作系统立刻进行回复,所以应用程序不会阻塞,可以进行其他任务,或继续进行系统调用,查询是否有要接收的数据。

此模型并不阻塞,但是需要循环查询,浪费CPU,低效。

python多模态模型搭建 python的模型_IO模型_02

  • 代码实现:
    在socket中,设置套接字对象.setblocking(False)可以变为非阻塞模型。
"""
服务端
"""
import socket
import time

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

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)  # 没有消息要接受,报错
                if len(data) == 0:  # 客户端断开链接
                    conn.close()  # 关闭conn
                    # 将无用的conn从r_list删除
                    # 为了不破坏原来列表的索引,将被删除的连接放到新列表中
                    del_list.append(conn)
                    continue
                conn.send(data.upper())
            except BlockingIOError:
                continue  # 从列表获取下一个连接,接收数据
            except ConnectionResetError:
                conn.close()
                del_list.append(conn)
        
        # 断开无用的链接
        for conn in del_list:
            r_list.remove(conn)
        del_list.clear()

        
"""
客户端
"""
import socket

client = socket.socket()
client.connect(('127.0.0.1',8081))

while True:
    client.send(b'hello world')
    data = client.recv(1024)
    print(data)

四、I/O多路复用模型

操作系统提供了多种监管机制,能够帮助我们监管socket对象和connect对象,并且能监管很多个,只要有事件触发,就会立刻给我们返回一个“可用”的信号。收到信号后,就可以调用recv()accept()等方法了。

select机制windows linux都有;poll机制只在linux有;poll和select都可以监管多个对象,但是poll监管的数量更多。如果需要跨平台就使用selectors模块,该模块会自动识别平台,使用对应的监管机制。

I/O多路复用模型不适用于单个连接。

python多模态模型搭建 python的模型_IO模型_03

  • 代码实现:
    python内置select(与机制同名)模块,能帮助我们使用select机制:
"""
服务端
"""
import socket
import select

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

server.setblocking(False)  # 改为非阻塞
# 要监管对象的列表
read_list = [server]

while True:
    # r_list是套接字对象,其他两个用不到,返回值为空
    r_list, w_list, x_list = select.select(read_list, [], [])
    for i in r_list:  
        # 判断是否为套接字对象
        if i is server:
            conn, addr = i.accept()
            # 将连接对象添加到监管的队列中
            read_list.append(conn)
        else:
            res = i.recv(1024)
            if len(res) == 0:
                i.close()
                # 将无效的被监管对象移除
                read_list.remove(i)
                continue
            print(res)
            i.send(b'hello python')

            
"""
客户端
"""
import socket

client = socket.socket()
client.connect(('127.0.0.1',8081))

while True:

    client.send(b'hello world')
    data = client.recv(1024)
    print(data)

五、异步I/O模型

异步IO模型是所有模型中效率最高的,也是使用最广泛的!

应用程序发起系统调用后,会得到立刻一个恢复,然后应用程序就可以去执行其他任务。而操作系统接收到数据后,会立刻给应用程序发送一个信号,表示之前的系统调用有结果了。

python多模态模型搭建 python的模型_非阻塞_04

  • 代码实现:
    实现异步I/O模型需要借助于asyncio模块。
import threading
import asyncio

@asyncio.coroutine
def hello():
    print('hello world %s'%threading.current_thread())
    yield from asyncio.sleep(1)  # 换成真正的IO操作
    print('hello world %s' % threading.current_thread())

loop = asyncio.get_event_loop()
tasks = [hello(),hello()]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()