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

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 模型各有优缺点,在不同的应用场景中可以选择合适的模型来提高程序的性能和效率。


http://www.kler.cn/a/599874.html

相关文章:

  • http代理的工作原理与功能应用
  • C++ 重构隐马尔可夫模型:从 Python 性能困境到高效运行的突破实录
  • Ubuntu版免翻墙搭建BatteryHistorian
  • 《Python机器学习基础教程》第2讲:监督学习与分类算法
  • 健康养生:铺就活力生活之路
  • 人工智能革命:技术演进图谱与人类文明重构路径
  • Android集成Facebook登录与分享的常见问题及解决方案
  • UE4-UE5虚幻引擎,前置学习一--Console日志输出经常崩溃,有什么好的解决办法
  • linux下基本命令和扩展命令(安装和登录命令、文件处理命令、系统管理相关命令、网络操作命令、系统安全相关命令、其他命令)欢迎补充噢
  • Netlify 的深度解析及使用指南
  • 使用 OpenCV 拼接进行图像处理对比:以形态学操作为例
  • 【机器学习】什么是决策树?
  • HTML图像标签的详细介绍
  • win32汇编环境,网络编程入门之十一
  • COBOL语言的微服务
  • 2025-03-24 学习记录--C/C++-PTA 习题7-4 求矩阵各行元素之和
  • MAC terminal
  • tcping 命令的使用,ping IP 和端口
  • Java编写体彩双色球
  • 2024年MathorCup数学建模D题量子计算在矿山设备配置及运营中的建模应用解题文档与程序