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

文件IO和多路复用IO

目录

前言

一、文件 I/O

1.基本文件 I/O 操作

1.1打开文件

1.2读取文件内容 (read)

1.3写入文件 (write)

1.4关闭文件 (close)

2.文件指针

二、多路复用 I/O

1.常用的多路复用 I/O 模型

1.1select

1.2poll

1.3epoll

2.使用 select、poll 和 epoll 进行简单的 I/O 监控

3.select、poll 和 epoll 三种 I/O 多路复用模型的对比


前言

  • 文件 I/O 是程序与外部数据交互的基础,可以通过读取和写入文件实现数据持久化。文件 I/O 的操作相对简单,适用于普通的数据读写场景。
  • 多路复用 I/O 则是一种高级 I/O 操作模式,能够有效地处理多个文件描述符的 I/O 事件,广泛应用于网络编程中,特别是在高并发服务器中发挥着重要作用。常用的多路复用 I/O 模型包括 selectpollepoll

一、文件 I/O

文件 I/O(Input/Output,输入/输出)指的是计算机程序与文件进行交互的过程,这些文件通常存储在磁盘上。文件 I/O 是程序与外部数据交互的基础,能够实现数据的存储、读取和处理。

1.基本文件 I/O 操作

1.1打开文件

  • 在进行文件操作之前,需要先打开文件。open 函数用于打开文件,并返回一个文件对象,供后续操作使用。
  • 语法:file_object = open(file_name, mode)
  • 常用模式:
    • "r": 读取(默认)
    • "w": 写入(会覆盖原有文件)
    • "a": 追加(在文件末尾追加内容)
    • "b": 二进制模式(如 "rb", "wb" 等)
    • "+": 更新模式(读写都可以,如 "r+", "w+"

1.2读取文件内容 (read)

  • 打开文件后,可以使用 read()readline()readlines() 方法读取文件内容。
  • read(size):读取文件中 size 个字节内容,如果不指定 size,则读取整个文件。
  • readline():按行读取文件,返回文件中的一行。
  • readlines():返回文件中的所有行,结果是一个包含每行内容的列表。
with open("example.txt", "r") as file:content = file.read()print(content)

1.3写入文件 (write)

  • 使用 write() 方法将字符串写入文件中。如果文件是以 "w" 模式打开的,写入时会覆盖文件内容。
  • 如果想逐行写入,可以使用 writelines() 方法,这个方法接受一个字符串列表,每个字符串将作为一行写入文件。
with open("example.txt", "w") as file:file.write("Hello, World!\n")file.writelines(["Line 1\n", "Line 2\n"])

1.4关闭文件 (close)

操作完成后,应当使用 close() 关闭文件,以释放系统资源。不过,使用 with 语句可以自动关闭文件。

file = open("example.txt", "r")
# 执行操作
file.close()  # 关闭文件

2.文件指针

  • 文件指针是指示文件中当前读写位置的标记。
  • tell():获取文件指针当前位置。
  • seek(offset, from_what):移动文件指针到指定位置。offset 表示偏移量,from_what 表示参考点(0: 文件开头, 1: 当前位置, 2: 文件结尾)。

二、多路复用 I/O

多路复用 I/O 是一种高级 I/O 操作模式,允许一个进程同时监听多个文件描述符(如文件、网络连接等),并根据事件发生情况进行相应处理。它的优势在于避免了传统阻塞 I/O 操作的等待时间,提升了并发处理的效率。

1.常用的多路复用 I/O 模型

1.1select

  • select 是一种跨平台的 I/O 多路复用接口,能够监控一组文件描述符(包括套接字),当其中的一个或多个描述符准备好进行 I/O 操作时,select 返回并指示哪些描述符可以进行操作。
  • 它的基本思想是通过单个系统调用等待多个文件描述符中的任何一个变得可读、可写或有错误发生。
import select
import socket# 创建 socket 对象
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('localhost', 8080))
sock.listen(5)inputs = [sock]
while True:readable, writable, exceptional = select.select(inputs, [], [])for s in readable:if s is sock:conn, addr = s.accept()inputs.append(conn)else:data = s.recv(1024)if data:print("Received:", data.decode())else:inputs.remove(s)s.close()

1.2poll

  • pollselect 的改进版本,克服了 select 的一些限制(如文件描述符数量限制)。
  • poll 使用一个 poll 对象来监控多个文件描述符。它的行为和 select 类似,但性能更好,特别是在监控大量描述符时。
import select
import socketsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('localhost', 8080))
sock.listen(5)poller = select.poll()
poller.register(sock, select.POLLIN)fd_to_socket = {sock.fileno(): sock}
while True:events = poller.poll()for fd, flag in events:s = fd_to_socket[fd]if flag & select.POLLIN:if s is sock:conn, addr = s.accept()poller.register(conn, select.POLLIN)fd_to_socket[conn.fileno()] = connelse:data = s.recv(1024)if data:print("Received:", data.decode())else:poller.unregister(fd)s.close()del fd_to_socket[fd]

1.3epoll

  • epoll 是 Linux 提供的一种高效的多路复用 I/O 模型,适用于大量并发连接场景。相比 selectpollepoll 更加高效,因为它采用了事件通知机制,避免了轮询的开销。
  • epoll 可以分为水平触发(Level-Triggered,LT)和边缘触发(Edge-Triggered,ET)两种模式,ET 模式更加高效,但编程更加复杂。
import select
import socketsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('localhost', 8080))
sock.listen(5)epoll = select.epoll()
epoll.register(sock.fileno(), select.EPOLLIN)fd_to_socket = {sock.fileno(): sock}
while True:events = epoll.poll()for fd, event in events:s = fd_to_socket[fd]if event & select.EPOLLIN:if s is sock:conn, addr = s.accept()epoll.register(conn.fileno(), select.EPOLLIN)fd_to_socket[conn.fileno()] = connelse:data = s.recv(1024)if data:print("Received:", data.decode())else:epoll.unregister(fd)s.close()del fd_to_socket[fd]

2.使用 selectpollepoll 进行简单的 I/O 监控

import select
import socket
import sysdef create_server_socket():server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)server_socket.bind(('localhost', 8080))server_socket.listen(5)return server_socketdef handle_select(server_socket):inputs = [server_socket]while True:readable, writable, exceptional = select.select(inputs, [], [])for s in readable:if s is server_socket:conn, addr = s.accept()inputs.append(conn)else:data = s.recv(1024)if data:s.send(data)else:inputs.remove(s)s.close()def handle_poll(server_socket):poller = select.poll()poller.register(server_socket, select.POLLIN)fd_to_socket = {server_socket.fileno(): server_socket}while True:events = poller.poll()for fd, flag in events:s = fd_to_socket[fd]if flag & select.POLLIN:if s is server_socket:conn, addr = s.accept()poller.register(conn.fileno(), select.POLLIN)fd_to_socket[conn.fileno()] = connelse:data = s.recv(1024)if data:s.send(data)else:poller.unregister(fd)s.close()del fd_to_socket[fd]def handle_epoll(server_socket):epoll = select.epoll()epoll.register(server_socket.fileno(), select.EPOLLIN)fd_to_socket = {server_socket.fileno(): server_socket}while True:events = epoll.poll()for fd, event in events:s = fd_to_socket[fd]if event & select.EPOLLIN:if s is server_socket:conn, addr = s.accept()epoll.register(conn.fileno(), select.EPOLLIN)fd_to_socket[conn.fileno()] = connelse:data = s.recv(1024)if data:s.send(data)else:epoll.unregister(fd)s.close()del fd_to_socket[fd]if __name__ == "__main__":if len(sys.argv) != 2:print("Usage: python3 server.py <select|poll|epoll>")sys.exit(1)mode = sys.argv[1]server_socket = create_server_socket()if mode == "select":handle_select(server_socket)elif mode == "poll":handle_poll(server_socket)elif mode == "epoll":handle_epoll(server_socket)else:print("Invalid mode. Use 'select', 'poll', or 'epoll'.")sys.exit(1)

3.selectpollepoll 三种 I/O 多路复用模型的对比

  • select 适用于小规模并发应用,跨平台支持广泛,但在处理大量文件描述符时性能较差。
  • poll 解决了 select 的文件描述符限制问题,适合中小规模并发连接,但在性能上不如 epoll
  • epoll 是处理大规模并发连接的最佳选择,具有出色的扩展性和性能,但仅在 Linux 系统上可用,并且编程复杂度较高。

http://www.mrgr.cn/news/7205.html

相关文章:

  • tcp 网络通信及抓包工具的使用
  • MySQL 1130错误原因及解决方案
  • 如何选择高品质科研实验室用太阳光模拟器
  • 【Android笔记】Android APK编译打包流程
  • 【TS】5 在React中使用TS
  • 推荐一个java低代码开发平台-橙单
  • ffmpeg.exe命令行常见应用
  • 金蝶云星空开发简单账表《物料年采购入库报表》
  • pyro 教程 时间序列 单变量,重尾,python pytorch,教程和实例 Forecasting预测,布朗运动项、偏差项和协变量项
  • 19.缓存的认识和基本使用
  • AMEYA360:芯讯通5G RedCap+智慧电力,SIM8230“轻”装上阵
  • 分析Facebook在区块链技术中的应用与前景
  • 谷歌chrome浏览器显示“版本太旧”又无法更新情况下,如何关闭“Chrome版本太旧”提示,包括直接启动Google浏览器,或者通过其他应用启动
  • 解决使用matplotlib不显示中文的问题
  • Android系统架构
  • 神经网络动画讲解 - 神经网络工作流程
  • F5G全光网实践
  • 机器学习:逻辑回归实现下采样和过采样
  • Spring 事务和事务传播机制
  • 做谷歌seo如何创建良好的用户体验?