文件IO和多路复用IO

news2024/11/15 10:56:25

目录

前言

一、文件 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 socket

sock = 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()] = conn
            else:
                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 socket

sock = 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()] = conn
            else:
                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 sys

def 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_socket

def 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()] = conn
                else:
                    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()] = conn
                else:
                    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.coloradmin.cn/o/2071120.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于vue框架的北城招聘管理平台题目7lly3(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;用户,企业,企业信息,职位类型,职位信息,简历信息,职位应聘,求职意愿,面试信息,录取信息,实习信息,冻结信息,解冻信息 开题报告内容 基于Vue框架的北城招聘管理平台 开题报告 一、引言 随着互联网的飞速发展和企业对人才需求的不断增…

无人机之如何利用无人机进行地形测绘

一、无人机的选择 多旋翼无人机&#xff1a;多旋翼无人机具有较好的稳定性和悬停能力&#xff0c;适用于复杂地形和需要高精度影像测绘任务。 固定翼无人机&#xff1a;固定翼无人机飞行速度快&#xff0c;续航能力强&#xff0c;更适合大面积的地形测绘工作。 消费级无人机…

python怎么删除模块

1、用命令行删除 安装pip $ wget https://bootstrap.pypa.io/get-pip.py $ python get-pip.py 删除指定的模块或者包&#xff1a; pip uninstall xxx 2、手动删除 去Python的第三方模块或包的存放位置进行手工删除文件和文件夹&#xff0c;然后删除easy-install.pth文件中的相…

Canvas实现电子签名功能

实现代码如下&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Canvas实现手写板</t…

开发指南056-定时任务

业务场景中定时任务很常见。平台实现定时任务的原则如下&#xff1a; 1、定时任务的定义在业务库&#xff08;没必要集中到核心库&#xff0c;另外定时任务的服务要访问业务库&#xff09;。 2、定时任务的服务为独立微服务。 平台的定时任务基于&#xff1a; <dependenc…

20240824 每日AI必读资讯

谷歌搜索引擎全面揭秘&#xff01;近百份文档泄露&#xff0c;博主爆肝数周逆向工程 - 继5月的文件泄露事件后&#xff0c;谷歌的搜索引擎又被掀了个底朝天。 - DeepMind发论文解释了Vizier系统的机制&#xff0c;博客作者Mario Fischer还对近百份文档做了彻底的调研分析&…

单位信息宣传考核投稿方法不对让我尝尽了苦头

自从我担任单位的信息宣传员以来,便深刻体会到“信息宣传”四个字背后的重量。每月的信息宣传考核任务就像一座大山,压在我心头。起初,我像大多数同行一样,习惯于通过电子邮件向各大媒体投稿,但这种方式让我尝尽了苦头。 记得开始尝试通过邮箱投稿时,我满怀信心地将精心准备的文…

C语言-内存管

内存区间 全局/静态存储区 不仅仅包含全局变量&#xff0c;还包含静态变量&#xff08;包括在函数内部定义的静态局部变量&#xff09;、字符串常量以及main函数开始执行之前就被初始化的所有其他数据。这些数据的生命周期贯穿整个程序执行期间。 对于一个C语言程序而言&…

SQL-DQL-数据查询语言

数据查询语言 1、基础查询 2、条件查询 3、聚合函数 4、分组查询 5、分页查询 6、案例 7、执行顺序 select 字段列表 from 表名列表 where 条件列表 group by 分组字段列表 having 分组后条件列表 order by 排序字段列表 limit 分页参数1、基础查询 select 字段1[as 别…

OpenCV与AI深度学习 | 基于改进YOLOv8的景区行人检测算法

本文来源公众号“OpenCV与AI深度学习”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;基于改进YOLOv8的景区行人检测算法 作者&#xff1a;贵向泉&#xff0c;刘世清&#xff0c;李立等 来源&#xff1a;《计算机工程》期刊 编…

Linux 命令集合

1. linux 系统版本 1.1 linux系统的分类 linux系统&#xff0c;主要分Debian系和RedHat系&#xff0c;还有其它自由的发布版本。 1、Debian系主要有Debian&#xff0c;Ubuntu&#xff0c;Mint等及其衍生版本&#xff1b; 2、RedHat系主要有RedHat&#xff0c;Fedora&#xf…

AI可预测地震,科技的“预知未来”?

在科幻小说和电影中&#xff0c;预知未来的能力总是让人向往。而在现实世界中&#xff0c;科学家们正利用人工智能&#xff08;AI&#xff09;技术&#xff0c;向着预测自然灾害这一“未来”的目标迈进。 近日&#xff0c;德州大学奥斯汀分校&#xff08;UT Austin&#xff09;…

【C++】C++的模板初识

目录 思维导图大纲&#xff1a; 1. 什么是模板&#xff1f; 2. 模板的分类 区别&#xff1a;函数模版和模版函数 / 类模版和模版类 2.1 函数模板 2.1.1 用法 2.1.2 原理 2.1.3 函数模板的实例化 2.1.4 模板参数的匹配原则 2.2 类模板 2.2.1 用法 2.2.2 原理 …

Linux--gdb的常用命令

目录 前言 一、gdb是什么&#xff1f; 二、常用命令 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 对于程序有两个版本&#xff0c;一个是debug版和release版&#xff0c;要想进行调试必须使用debug版本&#xff0c;再Linux上进行调试就要用到调试器…

660高数刷题

1 周期函数的周期等于上下限的差值则值相等 2 3 4 5 6 泰勒公式要展开到多少阶

快速幂算法【算法 08】

快速幂算法详解 在计算机编程中&#xff0c;快速幂算法是一种高效计算大整数幂次的算法。相较于直接的暴力计算&#xff0c;快速幂能够在对数级别的时间复杂度下完成运算&#xff0c;因此它在许多算法和问题中&#xff08;如数论、组合数学、密码学等&#xff09;都有广泛的应用…

web常见漏洞之——SSRF

ssrf 概述工具环境实验一 概述 SSRF(Server-Side Request Forgery)叫做服务器请求伪造&#xff0c;因为服务器提供了从其他服务器应用获取数据的功能且没有对目标地址进行过滤和限制导致黑客可以对服务器请求的地址进行伪造。 ssrf漏洞的主要用处就是对服务器进行资源扫描&am…

YOLOv9改进策略【损失函数篇】| Slide Loss,解决简单样本和困难样本之间的不平衡问题

一、本文介绍 本文记录的是改进YOLOv9的损失函数&#xff0c;将其替换成Slide Loss&#xff0c;并详细说明了优化原因&#xff0c;注意事项等。Slide Loss函数可以有效地解决样本不平衡问题&#xff0c;为困难样本赋予更高的权重&#xff0c;使模型在训练过程中更加关注困难样…

【回溯Ⅱ】组合问题

用回溯&#xff08;递归&#xff09;解决组合问题 第一类组合问题77.组合216.组合问题Ⅲ 第二类组合问题39. 组合总和递归法一&#xff1a;组合位置填空递归法二&#xff1a;遍历数组 40. 组合总和 II递归法一&#xff1a;组合位置填空递归法二&#xff1a;遍历数组❌ 常规思路…

SpringBoot集成kafka-监听器手动确认接收消息(主要为了保证业务完成后再确认接收)

SpringBoot集成kafka-监听器手动确认接收消息 1、说明2、示例2.1、application.yml2.2、消费者2.3、生产者2.4、测试类2.5、测试 1、说明 kafak中默认情况下是自动确认消息接收的&#xff0c;也就是说先启动消费者监听程序&#xff0c;再启动生产者发送消息&#xff0c;此时消…