UNIX环境高级编程->高级IO(概念篇)

UINX环境

  • 常见的操作系统比如Linux 和 MacOS都是基于UNIX的。它们都继承了UNIX的许多特性和设计理念。因此,它们的高级I/O技术确实是建立在UNIX基础之上的。Linux和macOS都提供了丰富的高级I/O功能和API,利用了UNIX系统调用和原则。这些功能包括非阻塞I/O、多路复用I/O(如Linux上的select()poll()epoll(),以及macOS上的kqueue)、异步I/O(aio_*函数),以及其他更高级的I/O技术。这篇文章主要介绍在Linux环境下得高级IO。

这篇文章主要介绍五种IO模型,分别是:

  • 阻塞式IO
  • 非阻塞式IO
  • 信号驱动式IO
  • 多路转接IO
  • 异步IO

IO

什么是IO?

IO,就是Input(输入),Output(输出)的简称。 最简单的使用C语言调用printf函数时,就是向显示器输出数据。
调用scanf函数时,就是从标准输入键盘读入数据。这就是最基本的IO,一般称之为标准IO。还有一些文件IO。比如readwirte。这些函数,从文件中输入或者向文件中输出时,这也是IO操作,一般称之为文件IO。在比如网络中socket套接字中的recvsend这些函数,从socket套接字中输入或者输出时,都是IO操作,一般称之为网络IO。

而应用层在调用printfwirtesend这些函数时,本质是把数据从用户层拷贝到操作系统内核层中的缓冲区中。在数据被写入到内核缓冲区后,操作系统会负责将数据从内核缓冲区传输到实际的输出设备或目标,比如显示器、文件或网络。这个过程可以是立即发生,也可以是延迟到适当的时机再进行。

image.png

同理,调用scnafreadrecv这些函数时,本质是从操作系统内核缓冲区中将数据拷贝到用户层中。这些函数本质也就是拷贝函数。

而在IO时,大部分的时间是在等待,只有有数据的时候,才会进行拷贝。举个简单的例子。比如调用scanf时,不从键盘输入时,就不会读取数据。进程就会一直阻塞等待,只有当用户从键盘中输入完数据按下回车时,才会读取。

根据上面的认识,可以建立一个共识,那就是IO = 等待 + 拷贝。而要进行拷贝,必须先要判断条件是否成立(即内核缓冲区是否有空间 或者有数据)。

在进程等待的这段时间内,如果进程一直判断内核的接收缓冲区是否有数据,有数据就进行读取。一直进行判断,肯定会带来CPU资源的消耗。大佬们就会想出解决办法,让进程不要一直进行判断,根据特定的规则,来判断内核缓冲区的状态。将其称之为高效IO。

所谓的高效IO,就是在单位时间内,拷贝的数据量越大,进行判断的次数越少。根据这个解决思路,有了各种IO模型。
就是上面提到的五种IO模型,他们并不都是高效的,只有部分是高效的,最值得学习的是IO多路转接和非阻塞IO。这篇文章也会重点介绍这两种IO模型。

先简单得认识一下这五种模型,在详细介绍其中高效得。

阻塞式IO

阻塞式IO(Blocking IO)是一种常见的IO模型,其特点是当应用程序执行IO操作时,如果数据没有准备好或无法立即进行IO操作,应用程序会进入阻塞状态,直到数据准备就绪或IO操作完成为止。所有的套接字默认都是阻塞方式

阻塞式IO的工作流程通常如下:

  1. 应用程序发起IO操作(如读取文件、接收网络数据等)。
  2. 如果数据已经准备好,或者可以立即进行IO操作,IO操作会立即完成,应用程序继续执行后续代码。
  3. 如果数据尚未准备好,或者无法立即进行IO操作(如网络数据尚未到达、文件尚未准备好等),应用程序会进入阻塞状态,暂时挂起,直到数据准备就绪或IO操作完成。
  4. 一旦数据准备就绪或IO操作完成,应用程序会解除阻塞状态,继续执行后续代码。

阻塞式IO的优点是实现简单,易于理解和使用。但它也存在一些缺点,主要包括:

  • 资源浪费:在数据未准备就绪时,应用程序会一直等待,占用CPU资源。这可能导致系统资源的浪费。
  • 性能不佳:在大量IO操作时,阻塞式IO可能会导致程序的性能下降,特别是在需要等待大量IO操作完成时。
  • 不适合高并发环境:在高并发环境下,阻塞式IO可能会导致系统资源耗尽,无法满足大量并发IO请求的需求。

阻塞式IO存在一些缺点,但在某些场景下仍然是一种合适的IO模型,特别是在简单的应用中或者IO负载较轻的情况下。

非阻塞IO

非阻塞IO(Non-blocking IO)是一种IO模型,其特点是在应用程序执行IO操作时,如果数据尚未准备好或无法立即进行IO操作,应用程序不会进入阻塞状态,而是立即返回一个错误码或指示数据未就绪的状态,让应用程序可以继续执行其他任务。

非阻塞式IO的工作流程通常如下:

  1. 应用程序发起非阻塞IO操作(如读取文件、接收网络数据等)。
  2. 如果数据已经准备好,或者可以立即进行IO操作,IO操作会立即完成,应用程序继续执行后续代码。
  3. 如果数据尚未准备好,或者无法立即进行IO操作(如网络数据尚未到达、文件尚未准备好等),IO操作会立即返回一个错误码或指示数据未就绪的状态,应用程序可以继续执行其他任务,而不是等待数据准备就绪。
  4. 应用程序可以周期性地轮询IO操作的状态,直到数据准备就绪或IO操作完成。

非阻塞IO的优点包括:

  • 资源利用率高:应用程序不会一直等待数据准备就绪,而是可以继续执行其他任务,提高了系统的资源利用率。
  • 适合高并发环境:在高并发环境下,非阻塞IO可以有效地处理大量IO请求,而不会导致系统资源的耗尽。

非阻塞IO往往需要程序员循环的方式反复尝试读写文件描述符, 这个过程称为轮询. 这对CPU来说是较大的浪费, 一 般只有特定场景下才使用。

信号驱动式IO

信号驱动IO(Signal-driven IO)是一种IO模型,其基本思想是应用程序在发起IO操作后,不需要等待数据准备就绪或IO操作完成,而是继续执行其他任务。当数据准备就绪或IO操作完成时,操作系统会发送一个信号给应用程序,通知其进行IO操作。

信号驱动IO的工作流程通常如下:

  1. 应用程序发起信号驱动IO操作(如读取文件、接收网络数据等)。
  2. 应用程序继续执行其他任务,不会被阻塞。
  3. 当数据准备就绪或IO操作完成时,操作系统会向应用程序发送一个信号(如SIGIO),通知其进行IO操作。
  4. 应用程序在接收到信号后,处理IO操作的结果,读取数据或者进行其他后续处理。

信号驱动IO的优点包括:

  • 非阻塞:应用程序不会因为IO操作而被阻塞,可以继续执行其他任务,提高了系统的并发能力和响应速度。
  • 异步:应用程序在发起IO操作后,不需要等待IO操作完成,而是在IO操作完成后收到信号再进行处理,实现了异步IO。
  • 适用于高并发环境:在高并发环境下,信号驱动IO可以有效地处理大量IO请求,而不会导致系统资源的耗尽。
  • 简化编程:相对于非阻塞IO,信号驱动IO模型能够降低编程复杂度,因为应用程序不需要周期性地轮询IO操作的状态,而是在IO操作完成后收到信号再进行处理。

然而,信号驱动IO也存在一些缺点,如:

  • 信号处理的复杂性:应用程序需要编写信号处理函数来处理IO操作完成的信号,这可能会增加代码的复杂性和维护成本。
  • 可移植性:不同操作系统对信号驱动IO的支持程度不同,可能存在一定的可移植性问题。

信号驱动IO在一些情况下可以是高效的,特别是在需要处理大量并发IO请求时。然而,它也有一些局限性,需要根据具体的应用场景和需求来选择是否使用。

多路转接IO

IO多路复用(IO Multiplexing)是一种高效的IO模型,它允许应用程序同时监视多个IO事件,当其中任何一个IO事件就绪时,应用程序可以进行相应的处理。这样可以减少了IO操作的轮询次数,提高了系统的效率和性能。

常见的IO多路复用技术包括select、poll、epoll等。

  • select:select是最早的IO多路复用技术之一,在UNIX系统中广泛使用。它通过select函数来监视多个文件描述符的IO状态,并在其中任何一个IO事件就绪时返回。但select有一些限制,例如监视的文件描述符数量有限,时间复杂度较高等。
  • poll:poll是select的改进版,也是一种IO多路复用技术。它通过poll函数来监视多个文件描述符的IO状态,并在其中任何一个IO事件就绪时返回。相比于select,poll没有文件描述符数量的限制,但效率仍然不高。
  • epoll:epoll是Linux系统下的IO多路复用技术,是select和poll的替代品,也是目前性能最好的IO多路复用技术之一。它通过epoll_ctl和epoll_wait两个函数来监视文件描述符的IO状态,并在其中任何一个IO事件就绪时返回。epoll具有高效、可扩展等特点,适用于高并发的IO场景。

IO多路复用的优点包括:

  1. 高效:IO多路复用可以减少IO操作的轮询次数,提高系统的效率和性能。
  2. 可扩展:IO多路复用技术通常支持大量的文件描述符,能够满足高并发的IO请求。
  3. 简化编程:相比于其他IO模型,IO多路复用可以降低编程复杂度,提高代码的可读性和可维护性。

总之,IO多路复用是一种高效的IO模型,适用于需要处理大量并发IO请求的场景,如网络服务器等。在选择IO模型时,可以根据具体的应用需求和性能要求来选择合适的IO多路复用技术。

异步IO

异步IO是一种IO模型,其核心思想是应用程序在发起IO操作后不需要等待IO操作完成,而是可以继续执行其他任务。当IO操作完成后,操作系统会通知应用程序,并将IO操作的结果传递给应用程序进行处理。

异步IO的工作流程通常如下:

  1. 应用程序发起异步IO操作(如读取文件、接收网络数据等)。
  2. 应用程序继续执行其他任务,不会被阻塞。
  3. 当IO操作完成后,操作系统会向应用程序发送通知,告知IO操作的结果。
  4. 应用程序在接收到通知后,处理IO操作的结果,读取数据或者进行其他后续处理。

异步IO通常需要操作系统提供支持,以便操作系统能够在IO操作完成后通知应用程序。在不同的操作系统中,异步IO的实现方式可能会有所不同。

异步IO的优点包括:

  • 非阻塞:应用程序不需要等待IO操作完成,而是可以继续执行其他任务,提高了系统的并发能力和响应速度。
  • 高效:异步IO可以在IO操作完成后立即进行下一步处理,而不需要额外的等待时间,因此可以提高系统的效率和性能。
  • 适用于高并发环境:在高并发环境下,异步IO可以有效地处理大量IO请求,而不会导致系统资源的耗尽。
  • 简化编程:相比于其他IO模型,异步IO可以降低编程复杂度,因为应用程序不需要周期性地轮询IO操作的状态,而是在IO操作完成后收到通知再进行处理。

然而,异步IO也存在一些局限性,如:

  • 实现复杂性:异步IO的实现可能较为复杂,需要操作系统提供支持,并且需要编写异步IO的处理逻辑,这可能会增加代码的复杂性和维护成本。
  • 可移植性:不同操作系统对异步IO的支持程度不同,可能存在一定的可移植性问题。

综上所述,异步IO在一些情况下可以是高效的,特别是在需要处理大量并发IO请求时。然而,它也有一些局限性,需要根据具体的应用场景和需求来选择是否使用。

专业术语太多 看不懂? 没关系,外卖总点过吧。

阻塞IO: 想象一下你在等待外卖送到家。你打电话给外卖店订购食物,然后你必须一直在家等待,直到外卖送到。在这个过程中,你不能做其他事情,而是一直在等待外卖到达。

非阻塞IO: 现在你改变了策略,不再一直等待外卖到达,而是每隔一段时间就去看一次外面是否有外卖员。如果外卖员还没到,你就继续等待,否则就接收外卖。这样,你可以在等待外卖的同时做其他事情,不必一直停留在家中。

多路复用IO: 这次你和朋友一起等待外卖,你们决定轮流去看外面是否有外卖员。每个人都负责一段时间内的外卖观察,如果有外卖员到达,就通知其他人,然后大家一起去接收外卖。这样,大家可以共同等待外卖,而不必每个人都去看。

信号驱动IO: 现在你和朋友们一起等待外卖,但是你们并不一直在关注外面是否有外卖员,而是等外卖员到达后,外卖员会按门铃或敲门,通知你们外卖已经送到。这时,你们就会立即接收外卖。这样,你们可以在等待外卖的过程中做其他事情,不必一直注意外面的情况。

异步IO: 最后,你和朋友们订购了外卖,但是你们并不需要自己去等待外卖的到达。相反,你们委托了一个专门的外卖服务,他们会负责外卖的送达,并在外卖送到后通知你们。这样,你们可以完全不用关注外卖的送达过程,而是在等待的同时做其他的事情,直到外卖送到。

高级IO的几个重要概念

同步 VS 异步

  • 同步IO

    • 同步IO是指程序在执行IO操作时会阻塞(或等待),直到IO操作完成为止。
    • 在同步IO中,程序会按照顺序执行,每个IO操作都必须等待上一个IO操作完成后才能继续执行。
    • 例如,当程序调用读取文件的操作时,在读取完成之前,程序会一直等待,直到文件中的数据读取完毕后才能继续执行后续代码。
  • 异步IO

    • 异步IO是指程序在执行IO操作时不会阻塞,而是可以同时执行其他任务。
    • 在异步IO中,程序不必等待IO操作完成,而是可以继续执行其他任务,当IO操作完成时,会通过回调函数或其他方式来通知程序。
    • 例如,当程序调用异步读取文件的操作时,程序可以继续执行后续代码,不必等待文件读取完成,而是在文件读取完成后通过回调函数来处理读取的数据。

再简单的理解就是同步与异步的本质区别就是有没有参与IO的过程。异步不参与IO的过程,只是发起IO。同步则需要参与IO的过程。结合外卖的例子很好理解。五种IO模型中,除了异步IO,其余都是同步的。

注意
这里的同步要与多线程中的线程同步进行区分,他们二者毫无关系。
线程同步是指在多线程编程中,通过一些机制来确保多个线程之间的协调和合作,以达到正确、可靠地共享资源和避免竞争条件的目的。

阻塞VS非阻塞

  • 阻塞IO(Blocking IO)

    • 阻塞IO是指程序在执行IO操作时会被挂起(或阻塞),直到IO操作完成为止。
    • 当程序调用阻塞IO操作时,程序会一直等待,直到IO操作完成或超时才能继续执行后续代码。
    • 例如,当程序调用读取文件的操作时,在读取完成之前,程序会一直等待,直到文件中的数据读取完毕后才能继续执行后续代码。
  • 非阻塞IO(Non-blocking IO)

    • 非阻塞IO是指程序在执行IO操作时不会被挂起,而是可以立即返回,继续执行后续代码。
    • 当程序调用非阻塞IO操作时,如果IO操作无法立即完成,操作会立即返回一个错误码或特定的状态,而不是等待IO操作完成。
    • 例如,当程序调用非阻塞读取文件的操作时,如果文件中没有数据可读,读取操作会立即返回一个错误码或特定的状态,而不会一直等待数据可读。

这里需要注意一点,阻塞式IO和非阻塞式IO他们的IO效率是一样的,只是等待的方式不同而已。非阻塞再等待的时候可以做其他的事情。
关于非阻塞IO的详细介绍 非阻塞IO

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/3159.shtml

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

相关文章

【Linux】自定义协议——实现网络序列化和反序列化

欢迎来到Cefler的博客😁 🕌博客主页:折纸花满衣 🏠个人专栏:题目解析 🌎推荐文章:承接上文内容【Linux】应用层协议序列化和反序列化 目录 👉🏻代码实现如下Calculate.hp…

C语言-联合体基本概念

联合体的外在形式跟结构体非常类似,但它们有一个本质的区别:结构体中的各个成员是各自独立的,而联合体中的各个成员却共用同一块内存,因此联合体也称为共用体。 联合体内部成员的这种特殊的“堆叠”效果,使得联合体有如…

Ollama完成本地模型的运行

Ollama完成本地模型的运行 llama 3 8b很多pc都可以run起来,可以用这个练练手 简介 Ollama 是一个开源的大型语言模型(LLM)服务工具,它允许用户在本地运行和使用各种大型语言模型。Ollama 提供了一个命令行界面,支持多种流行的模型,如 Llama 3、Qwen 1.5、Mixtral、Gemma…

MapMagic 2 Biomes and Functions

MapMagic 2(免费)世界生成器官方模块。支持基于遮罩混合几个图形,从而可以在无限地形上混合不同的生物群落。也随附函数节点,从而可以在子图中执行复杂的生成过程。将它们视作含有输入和输出连接器的生物群落。请注意,必须使用 MapMagic 2 的现有安装才能使用该模块。 下…

(一)JVM实战——jvm的组成部分详解

前言 本节内容是关于java虚拟机JVM组成部分的介绍,通过其组成架构图了解JVM的主要组成部分。 正文 ClassFile:字节码文件 - javac:javac前端编译器将源代码编译成符合jvm规范的.class文件,即字节码文件 - class文件的结构组成&a…

数据变更捕获 (CDC):PostgreSQL 与 ClickHouse - 第一部分

本文字数:13442;估计阅读时间:34 分钟 审校:庄晓东(魏庄) 本文在公众号【ClickHouseInc】首发 简介 在之前的文章中,我们已经讨论了OLTP数据库(例如Postgres)和OLAP数据…

【go零基础】go-zero从零基础学习到实战教程 - 1项目表设计

既然是0基础,现在来写下设计思路,因为go-zero是个微服务架构,所以,哪怕是0基础,也从两个服务模块开始写起。 我们的目标是:最小可用微服务架构最佳实践! 好了,饼画完了。 第0部分写到…

504网关超时可能是哪些原因导致

当前随时互联网的发展普及,我们经常会使用到网站服务,许多网站为了提高打开速度,都会接入使用CDN。当我们在浏览网页或使用网络服务时,有时候可能有遇到网站打不开的情况,出现各式各样的错误代码,其中504网…

【注解和反射】通过反射动态创建对象、调用普通方法、操作属性

继上一篇博客【注解和反射】获取类运行时结构-CSDN博客 目录 八、通过反射动态创建对象 测试:通过反射动态创建对象 思考:难道没有无参的构造器就不能创建对象了吗?只要在操作的时候明确的调用类中的构造器并将参数传递进去之后,才可以实…

三维图形程序员必学-CGAL几何算法

GCAL几何算法库,涵盖了很多数学几何算法,矩阵运算、平面拟合、曲线拟合、曲面重建、网格优化、网格剖分、面线相交、布尔运算等等各种图形学几何相关的算法。 文章最后放了一个CGAL求点集拟合平面,投影求线的例子代码。 CGAL是一个开源代码库,官网连接GitHub - CGAL/cgal…

网络安全之弱口令与命令爆破(上篇)(技术进阶)

目录 一,什么是弱口令? 二,为什么会产生弱口令呢? 三,字典的生成 四,使用Burpsuite工具弱口令爆破 总结 一,什么是弱口令? 弱口令就是容易被人们所能猜到的密码呗,…

Linux动态追踪——eBPF

目录 摘要 1 什么是 eBPF 2 eBPF 支持的功能 3 BCC 4 编写脚本 5 总结 6 附 摘要 ftrace 和 perf 与 ebpf 同为 linux 内核提供的动态追踪工具,其中 ftrace 侧重于事件跟踪和内核行为的实时分析,perf 更侧重于性能分析和事件统计,与…

vim+xxd 编辑16进制

1. vim -b mib 2. 在vim 中执行 %!xxd, 这样就可以输入16进制: 3. 输入完成后,在vim中 执行 %!xxd -r 切换至原模式; 4. 保存退出即可 5. 重新打开mib文件:vim -b mib 6. 在vim 中执行 %!xxd, 查看是否符合预期:…

如何理解GDP、国民总收入(GNI)的区别和联系

国内生产总值和国民总收入是衡量一个国家(地区)经济状况和发展水平的两个重要总量指标。两者既有密切的联系,又有一定区别,用途都非常广泛。 一、GDP与GNI的基本概念 国内生产总值(Gross Domestic Product,GDP)&…

一个联合均值与方差模型的R包——dglm

目录 一、引言二、包的安装与载入三、模拟例子3.1 数据生成3.2 数据查看3.3 模型估计参数 一、引言 在 R 语言中,dglm 包是用于拟合双参数广义线性模型(Double Generalized Linear Models,简称 DGLMs)的一个工具。这类模型允许同…

模块三:二分——162.寻找峰值

文章目录 题目描述算法原理解法一:暴力查找解法二:二分查找 代码实现解法一:暴力查找解法二:CJava 题目描述 题目链接:162.寻找峰值 根据题意,需要使用O(log N)的时间复杂度来解决,得出本道题…

在美国站群服务器部署时如何保障从253个IP到1000个IP的无缝扩展?

在美国站群服务器部署时如何保障从253个IP到1000个IP的无缝扩展? 在当今企业的数字化转型中,服务器的部署和管理成为了保证业务连续性和拓展性的关键。尤其对于站群服务器来说,随着企业业务的增长和市场的扩展,需要从较小规模的253个IP地址…

AWTK 异形进度条控件发布

异形进度条控件。通过多边形来定义进度条的形状。 代码地址:https://gitee.com/zlgopen/awtk-widget-progress-polygon 特性 通过多边形定义进度条的形状支持通过图片来定义进度条的背景支持通过图片来定义进度条的前景 使用图片填充比使用颜色填充消耗更多的内…

数据结构练习-线性表定义与基本操作

----------------------------------------------------------------------------------------------------------------------------- 1. 线性表是( )。 A.一个有限序列,可以为空 B. 一个有限序列,不可以为空 C. 一个无限序列,可以为空…

第三次国土调查数据库字母缩写代表含义

CCWJQ拆除未尽区,CJDCQ村界调查区,CJDCQJX村界调查区界线,CLKZD测量控制点,CSKFBJ城市开发边界,CZCDYD城镇村等用地,DGX等高线,DLTB地类图斑,DZGY地质公园,FJMSQ风景名胜…