当前位置: 首页 > news >正文

IO模型种类

文章目录

      • 同步阻塞 I/O(Blocking I/O,BIO)
      • 同步非阻塞 I/O(Non-blocking I/O,NIO)
      • I/O 多路复用(I/O Multiplexing)
      • 信号驱动 I/O(Signal-driven I/O)
      • 异步 I/O(Asynchronous I/O,AIO)

在计算机编程和操作系统领域,I/O(输入/输出)模型是处理输入输出操作的不同方式,主要用于解决应用程序如何与外部设备(如磁盘、网络等)进行数据交互的问题。

同步阻塞 I/O(Blocking I/O,BIO)

  • 工作原理:在这种模型中,当应用程序发起一个 I/O 操作时,会一直阻塞等待,直到该操作完成并返回结果。在此期间,应用程序不能进行其他操作,CPU 资源被闲置。例如,在网络编程中,当调用 recv 函数接收数据时,程序会一直等待,直到有数据到达或者发生错误。
  • 应用场景:适用于连接数比较少且固定的场景,因为它的实现简单,但处理效率较低。比如一些传统的单机应用程序,对并发处理要求不高的场景。
  • 示例代码(Python)
import socket

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('localhost', 8888))
server_socket.listen(1)

print('Waiting for a connection...')
conn, addr = server_socket.accept()
print(f'Connected by {addr}')

data = conn.recv(1024)  # 阻塞等待数据
print(f'Received: {data.decode()}')

conn.sendall(b'Hello, client!')
conn.close()

同步非阻塞 I/O(Non-blocking I/O,NIO)

  • 工作原理:应用程序发起 I/O 操作后,不会阻塞等待结果,而是立即返回。应用程序需要不断地轮询检查 I/O 操作的状态,直到操作完成。这种方式可以让应用程序在等待 I/O 操作的同时进行其他任务,但频繁的轮询会消耗大量的 CPU 资源。
  • 应用场景:适用于连接数较多,但每个连接的 I/O 操作比较少的场景。例如,在一些简单的网络爬虫程序中,可以使用非阻塞 I/O 同时处理多个网络请求。
  • 示例代码(Python)
import socket

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('localhost', 8888))
server_socket.listen(1)
server_socket.setblocking(False)  # 设置为非阻塞模式

while True:
    try:
        conn, addr = server_socket.accept()
        print(f'Connected by {addr}')
        conn.setblocking(False)  # 设置连接为非阻塞模式
        try:
            data = conn.recv(1024)
            if data:
                print(f'Received: {data.decode()}')
                conn.sendall(b'Hello, client!')
        except BlockingIOError:
            pass
    except BlockingIOError:
        pass

I/O 多路复用(I/O Multiplexing)

  • 工作原理:通过一个机制(如 selectpollepoll 等)同时监视多个 I/O 事件,当其中任何一个 I/O 事件就绪时,通知应用程序进行相应的处理。应用程序在等待期间可以进行其他操作,避免了同步阻塞 I/O 中 CPU 资源的闲置。
  • 应用场景:适用于连接数较多且连接比较活跃的场景,如网络服务器。通过 I/O 多路复用,可以高效地处理大量的并发连接。
  • 示例代码(Python 使用 select
import socket
import select

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('localhost', 8888))
server_socket.listen(5)

inputs = [server_socket]

while True:
    readable, _, _ = select.select(inputs, [], [])
    for sock in readable:
        if sock is server_socket:
            conn, addr = server_socket.accept()
            print(f'Connected by {addr}')
            inputs.append(conn)
        else:
            data = sock.recv(1024)
            if data:
                print(f'Received: {data.decode()}')
                sock.sendall(b'Hello, client!')
            else:
                inputs.remove(sock)
                sock.close()

信号驱动 I/O(Signal-driven I/O)

  • 工作原理:应用程序发起 I/O 操作后,会立即返回,当 I/O 操作完成时,操作系统会发送一个信号通知应用程序。应用程序在等待信号期间可以进行其他操作。
  • 应用场景:相对较少使用,主要用于一些对实时性要求较高,但对数据传输量要求不高的场景。
  • 示例代码(C 语言):由于信号驱动 I/O 涉及底层系统调用和信号处理,代码较为复杂,以下是一个简单的伪代码示例:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <unistd.h>

// 信号处理函数
void sigio_handler(int signo) {
    // 处理 I/O 就绪事件
    printf("I/O is ready!\n");
}

int main() {
    int sockfd;
    struct sockaddr_in server_addr;

    // 创建套接字
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }

    // 设置服务器地址
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(8888);

    // 绑定套接字
    if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    // 监听连接
    if (listen(sockfd, 5) < 0) {
        perror("listen failed");
        exit(EXIT_FAILURE);
    }

    // 设置信号处理函数
    signal(SIGIO, sigio_handler);

    // 设置套接字为信号驱动 I/O 模式
    fcntl(sockfd, F_SETOWN, getpid());
    int flags = fcntl(sockfd, F_GETFL);
    fcntl(sockfd, F_SETFL, flags | O_ASYNC);

    while (1) {
        // 可以进行其他操作
        sleep(1);
    }

    return 0;
}

异步 I/O(Asynchronous I/O,AIO)

  • 工作原理:应用程序发起 I/O 操作后,立即返回,继续执行其他任务。操作系统会在 I/O 操作完成后,将结果直接返回给应用程序,而不需要应用程序进行额外的查询或处理。这种方式实现了真正的并发,应用程序的效率最高。
  • 应用场景:适用于对 I/O 性能要求极高的场景,如大型数据库服务器、高性能网络服务器等。
  • 示例代码(Python 使用 asyncio 库模拟异步 I/O)
import asyncio

async def handle_connection(reader, writer):
    data = await reader.read(1024)
    message = data.decode()
    print(f'Received: {message}')

    writer.write(b'Hello, client!')
    await writer.drain()

    writer.close()

async def main():
    server = await asyncio.start_server(
        handle_connection, 'localhost', 8888)

    addr = server.sockets[0].getsockname()
    print(f'Serving on {addr}')

    async with server:
        await server.serve_forever()

asyncio.run(main())

这些 I/O 模型各有优缺点,在不同的应用场景中可以选择合适的模型来提高程序的性能和效率。

相关文章:

  • 宫庭海:三十载光影铸就文化传奇
  • Python:单例模式魔法方法
  • 为何AI系统比以往任何时候都更需要红队测试
  • 光流 | 基于KLT算法的人脸检测与跟踪原理及公式,算法改进,matlab代码
  • C++20新特性:std::assume_aligned详解
  • 【GL010】C++
  • 数据结构初阶-二叉树的应用
  • 阿里开源的免费数据集成工具——DataX
  • AI加持后能自动化运维吗?
  • 数据库联表Sql语句(3个表)建一个新表(MySQL,Postgresql,SQL server)2
  • 【全队项目】智能学术海报生成系统PosterGenius(项目介绍)
  • Leetcode 刷题笔记 图论part05
  • 零售CMS革新驱动智慧建站转型
  • 重学Java基础篇—如何优雅的删除HashMap元素
  • 腾讯云DNS和Lego工具结合使用,可以方便地为你的域名自动申请和续期SSL证书。
  • Gone v2 配置管理4:连接Apollo配置中心
  • 智能手持终端PDA在设备巡检管理中的应用
  • 【C++ 继承】—— 青花分水、和而不同,继承中的“明明德”与“止于至善”
  • 大数据学习(83)-数仓建模理论
  • InnoDB 引擎核心知识点
  • 洞天寻隐·学林纪丨玉洞桃源:仇英青绿山水画中的洞天与身体
  • 常州市委原常委、组织部部长陈翔调任江苏省民宗委副主任
  • 我国外汇储备规模连续17个月稳定在3.2万亿美元以上
  • 陕南多地供水形势严峻:有的已呼吁启用自备水井
  • 韩国法院将李在明所涉案件重审日期延至大选后
  • 巴基斯坦外交部:印度侵略行径侵犯巴主权