472-I/O阻塞和非阻塞,同步和异步

2023-11-16

阻塞、非阻塞、同步、异步

典型的一次I/O的两个阶段是什么?
数据准备 和 数据读写
我们作为服务器,接收客户端的请求,得先监听客户端有没有数据过来,这是一个状态,还有就是数据过来了该怎么去读写,这又是一个状态。

实际上,阻塞,非阻塞,同步,异步,分别是这两种状态下的体系。

网络I/O阶段1
数据准备:根据系统IO操作的就绪状态
阻塞 : 让调用I/O的线程进入阻塞状态 ,数据准备好了就唤醒
非阻塞
不会改变线程的状态,通过返回值判断

sockfd相当于就是系统的文件描述符,代表1个I/O,创建的时候默认是阻塞,当我调用1个阻塞I/O的话,如果sockfd上没有数据可读,这个recv不会返回,造成当前线程阻塞,等待sockfd上有数据到来。
在这里插入图片描述
如果返回了,就是有数据可读了,接下去就是数据读写了。返回的是最终读的数据的大小。一直等着。

如果我们在创建sockfd的时候设置是非阻塞,recv的体现是:如果sockfd上没有数据到来的话,recv直接返回回来,不会造成当前线程阻塞。sockfd没有数据准备好的话,不断的空转CPU。

我们都是这么判断,如果size==-1的话,表示错误:
1、真的错误,是系统的内部错误,可能要close(sockfd)
2、如果size==-1&&errno==EAGAIN,表示正常的非阻塞返回,sockfd上没有网络事件发生

如果size= =0,表示网络对端关闭了连接,对端直接close(sockfd)
如果size>0,就是表示有数据过来了。
在这里插入图片描述
这2个错误号表示一样的情况

网络I/O阶段2
数据读写:根据应用程序和内核的交互方式
同步
异步

有2种同步和异步:
I/O的同步和异步
应用层并发的同步和异步
两者相似。
我们来看看网络I/O的同步和异步:

I/O同步:
线的上方是操作系统,线的下方就是应用程序
现在呢,我在应用程序上调用recv函数,这个sockfd我不管它工作在阻塞模式还是非阻塞模式,真的有数据准备好了之后(TCP的接收缓冲区有数据了,就是数据可读了),我们要读这个数据,这个buf是用户层自己定义的,recv就可以开始接收了,是应用程序卡在这里,从内核的TCP接收缓冲区搬数据到应用层上的buf,在搬的过程中,因为size>0,这就表示从内核搬了多少字节的数据,我们就要访问buf了,没搬完之前,不会进入到下面的if语句。搬完了,recv才返回过来,看看size是多少,就是搬了多少数据。
在这里插入图片描述
I/O同步的意思就是:当我调用网络I/O的接口,当I/O阶段1数据准备好之后,在数据读写的时候,应用层自己调用网络I/O接口自己去读写,都花在应用层上。
recv和send是同步的I/O接口

I/O异步
当我请求内核的时候,我比较关心sockfd上的数据,远端如果发过来数据,我需要读sockfd上的数据,我有一个buf,到时候如果有数据来了,内核能不能帮忙把数据放到buf里面,我再给内核注册一个sigio信号,也就是说,对一个操作系统级别的异步的I/O接口来说,我先塞给内核一个sockfd,对这个sockfd上的事件感兴趣,如果sockfd上有数据可读的话,麻烦操作系统内核把数据搬到buf里面。
内核把内核缓冲区-sockfd对应的TCP接收缓冲区的数据搬到buf里面,搬完以后,通过信号sigio给应用程序通知一下。应用程序就可以玩自己的了,做任何事清都可以。
当我们应用程序调用异步I/O接口的时候,我们就把sockfd,buf,sigio(通知方式,也可以通过回调,我们在这里用的是sigio)通过异步I/O接口都塞给了操作系统。应用程序做自己的任何事情都可以,当操作系统sigio通知你的时候,你看到的是buf的数据已经准备好了,应用程序不用搬,不用花应用程序的时间,不用像I/O同步一样一直阻塞等待recv或者空转。

在这里插入图片描述
异步,一定要记住这个词语:通知(异步最大的标识,是异步就有通知)

在同步I/O调用的时候,有数据准备好了,数据是应用程序自己花时间搬的,搬完以后,recv才返回,把数据从内核的接收缓冲区搬到用户的buf里面,耗的是应用程序的时间。

看操作系统有没有提供异步I/O接口让你调用。
异步I/O效率高哦!

linux的aio_read,aio_write就是典型的linux给我们提供的异步I/O接口。
在这里插入图片描述
在这里插入图片描述
就是aio_read需要的参数
就是应用程序在调用异步I/O接口需要传的参数,也就是给内核传的参数

Node.js基于异步非阻塞模式下的高性能服务器

在处理 IO 的时候,阻塞和非阻塞都是同步 IO。只有使用了特殊的 API 才是异步IO。
在这里插入图片描述
epoll是同步的I/O哦!
epoll_wait在调用的时候,我们传参数以后,最后一个参数的timeout,如果不自定义时间,相当于工作在阻塞状态,有事件发生,会返回发生事件的event,我们从event上读,如果event对应的事件是它在sockfd上有可读数据,我们读,调用recv,当然是我们应用程序自己读了。我们如果有设置timeout超时时间后,我们也得检查有没有发生事件event,没有的话,我们继续循环。

业务层面上的逻辑处理是同步还是异步:
同步就是 A操作等待B操作做完事情,得到返回值,继续处理。
异步就是A操作告诉B操作它感兴趣的事件以及通知方式,A操作继续执行自己的业务逻辑,等B监听到相应事件发生后,B会通知A,A开始相应的数据操作处理逻辑。

一个典型的网络IO接口调用,分为两个阶段,分别是“数据就绪”和“数据读写”,数据就绪阶段分为阻塞和非阻塞,表现得结果就是,阻塞当前线程或是直接返回。

同步表示A向B请求调用一个网络IO接口时(或者调用某个业务逻辑API接口时),数据的读写都是由请求方A自己来完成的(不管是阻塞还是非阻塞);

异步表示A向B请求调用一个网络IO接口时(或者调用某个业务逻辑API接口时),向B传入请求的事件以及事件发生时通知的方式,A就可以处理其它逻辑了,当B监听到事件处理完成后,会用事先约定好的通知方式,通知A处理结果。

同步阻塞 int size = recv(fd, buf, 1024, 0)
同步非阻塞 int size = recv(fd, buf, 1024, 0)
异步阻塞 (不合理,A本来就可以做其他事情,没有必要阻塞等待B做完事情给A通知,这是在浪费线程A的能力)
异步非阻塞(Node.js)

总结

阻塞,非阻塞,同步,异步描述的都是I/O的一些状态,一个典型的网络I/O包含2个阶段:数据准备(数据就绪)和数据读写,
比如说recv,传一个sockfd,buf,buf的大小,数据就绪就是远端有没有数据过来,就是内核相应的sockfd对应的TCP接收缓冲区是否有数据可读,当sockfd,当I/O工作在阻塞模式下的话,当我们调用recv的时候,如果数据没有就绪,recv是会阻塞当前的线程的。如果这个sockfd是工作在非阻塞模式下的话,当我们去调用系统I/O接口recv的时候,recv会直接返回的,我们都是这么判断,如果size==-1的话,表示错误
1、真的错误,是系统的内部错误,可能要close(sockfd)
2、如果size==-1&&errno==EAGAIN,表示正常的非阻塞返回,sockfd上没有网络事件发生。

如果size= =0,表示网络对端关闭了连接,对端直接close(sockfd)
如果size>0,就是表示有数据过来了。

如果是同步I/O,数据就绪的时候,远端有数据过来了,数据准备好了,开始进行读写了,应用程序调用recv这个接口,recv会继续,相当于应用程序花自己的时间,把数据从内核的TCP接收缓冲区拷贝到给recv传的buf(应用程序的缓冲区),拷贝数据的过程中,应用程序是一直等待数据拷贝完成后,recv才返回,应用程序才自己向后走。

如果是异步I/O的话,调用系统给我们提供异步I/O接口的时候,我们要传入sockfd(对应一个TCP接收缓冲区,从远端接收数据的),buf(如果有数据,要把内核缓冲区的数据搬到应用程序的缓冲区中)和通知方式(通过信号或者回调,告诉操作系统异步I/O,到时候内核负责监听sockfd上是否有数据可读,有的话把数据从内核的TCP缓冲区搬到应用程序传的buf上,内核最后通过应用程序告知他的通知方式来通知应用程序,应用程序就可以处理这些事情,而且数据已经拿到手了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

472-I/O阻塞和非阻塞,同步和异步 的相关文章

随机推荐

  • UE常用使用技巧

    UE使用技巧1 如何在行末添加指定字符如 方法 ctrl r 用 p全部替换 n即可 p n 2 如何删除空行 查找 p 替换为空即可 p 空 3 括号自动匹配 Ctrl b4 加书签 Ctrl F2 加书签 Alt F2 在多个书签中进行
  • 调试最长的一帧(第十天)

    依照惯例 先看总体流程 到了更新回调 一边抄一边记忆 OSG更新回调的作用与事件回调有类似之处 由专门的访问器对象 updateVisitor负责场景图形更新遍历 所有的节点和Drawable几何体对象都可以使用setUpdateCallb
  • 数据结构——【堆】

    一 堆的相关概念 1 1 堆的概念 1 堆在逻辑上是一颗完全二叉树 类似于一颗满二叉树只缺了右下角 2 堆的实现利用的是数组 我们通常会利用动态数组来存放元素 这样可以快速拓容也不会很浪费空间 我们是将这颗完全二叉树用层序遍历的方式储存在数
  • 小程序登录授权分析

    登录 小程序可以通过微信官方提供的登录能力方便地获取微信提供的用户身份标识 快速建立小程序内的用户体系 在小程序 微信生态体系中 每个用户会有唯一标识的OpenID和UnionID 使用他们可以帮助开发者优化自己的注册和登录逻辑 毕竟 在中
  • the application was unable to start correctly(0x000007b)解决方案

    什麼是錯誤代碼0xc000007b 如果您在Windows 10 8 7中看到 應用程式無法正確啟動 0xc000007b 錯誤 那麼您來對地方了 0xc000007b應用程式錯誤非常常見 與錯誤代碼0x80070002 0x8007005
  • SSL的“四次握手”

    第一次握手 客户端向服务端发送Client Hello报文 该报文中包含了支持的版本信息 加密组件等 加密组建包括加密算法 秘钥长度等内容 第二次握手 这个阶段服务器会向客户端发送三个报文 服务端收到请求后 如果支持SSL通信 会首先以Se
  • SQL Server数据备份

    SQL Server数据库 自动 手动 备份 sql 数据库自动备份 一 为备份文件建一个独立文件夹 sql data autobakup 方便区分 Win R 输入services msc进入服务管理界面查找sqlserver服务 复制此
  • pulseaudio使用过程中遇到的问题

    W pulseaudio main c This program is not intended to be run as root unless system is specified E pulseaudio core util c H
  • Self-study Python Fish-C Note-5 P20-P26 (part2)

    python 中的列表 Part 2 本文主要讲解了python中列表的使用 本文为自学B站上鱼C的python课程随手做的笔记 如有问题 欢迎大家批评指正 原视频链接 https www bilibili com video BV1c44
  • LeetCode算法心得——和可被 K 整除的子数组(前缀和+HashMap)

    大家好 我是晴天学长 同余定理的应用 需要的小伙伴可以关注支持一下哦 后续会继续更新的 1 和可被 K 整除的子数组 题目描述 给定一个整数数组 A 返回其中元素之和可被 K 整除的 连续 非空 子数组的数目 示例 输入 A 4 5 0 2
  • 【极简数据结构】快速了解并实现顺序表,速通玩家的最爱

    顺序表目录 前言 一 线性表 二 顺序表 1 顺序表的概念 2 接口函数 顺序表 初始化 顺序表 尾插 顺序表 打印 顺序表 销毁 顺序表 尾删 顺序表 头插 和 顺序表 扩容 优化顺序表 尾删 顺序表 头删 顺序表 查找 顺序表 任意po
  • Android如何安全的关闭线程

    正常情况下 当线程中的run方法执行完毕后 线程是会自动关闭 不需要我们手动去关闭的 如 new Thread new Runnable Override public void run 执行操作 start 该线程在run方法中的操作执行
  • C语言经典100例题(22)--两个乒乓球队进行比赛,各出三人。甲队为a, b, c三人,乙队为x, y, z三人。已抽签决定//比赛名单,有人向队员打听比赛的名单.a说他不和x比,c说他不和x, z

    目录 题目 问题分析 代码 运行结果 题目 两个乒乓球队进行比赛 各出三人 甲队为a b c三人 乙队为x y z三人 已抽签决定比赛名单 有人向队员打听比赛的名单 a说他不和x比 c说他不和x z比 请编程序找出三队赛手的名单 问题分析
  • linux屏蔽海外流量的两种方法

    方法一 使用大神的开源脚本 屏蔽指定国家地区的IP访问 wget https raw githubusercontent com iiiiiii1 Block IPs from countries master block ips sh s
  • RSA的C++语言描述简单实现

    文章目录 前言 代码仓库 代码特点 大 素 数讨论 部分资料 作者理解 代码 rsa h rsa cpp main cpp 结果 总结 参考资料 作者的话 前言 网络安全中RSA的C 语言描述简单实现 代码仓库 yezhening Prog
  • excel 生成sql

    参考文章 https blog csdn net m0 67695717 article details 127406830 新增语句 INSERT INTO table name column1 column2 VALUES A2 D2
  • 判断一个文件是否为CSV文件的Python代码

    在Python中 我们可以使用os模块的path splitext 函数来获取文件扩展名 然后判断这个扩展名是否为 csv 以下是一个示例代码 import os def is csv file file path file extensi
  • WSL2和Docker for Windows

    文章目录 一 Docker和WSL2概述 二 WSL安装使用 三 基于Docker导入任意WSL分发 参考资料 一 Docker和WSL2概述 Docker 是一个开源的应用容器引擎 让开发者可以打包他们的应用以及依赖包到一个可移植的容器中
  • git中出现“interactive rebase in progress; onto 11dde1e”错误分析与解决方案

    出错原因分析 进行提交前 需提前拉取远程仓库的代码 拉取之后 需要重新add commit 避免仓库的数据被修改 但是再次提交之后会出现上图的错误 原因 是因为你现在正在编辑的提交将要覆盖在 11ddele commited 之前使用过gi
  • 472-I/O阻塞和非阻塞,同步和异步

    阻塞 非阻塞 同步 异步 典型的一次I O的两个阶段是什么 数据准备 和 数据读写 我们作为服务器 接收客户端的请求 得先监听客户端有没有数据过来 这是一个状态 还有就是数据过来了该怎么去读写 这又是一个状态 实际上 阻塞 非阻塞 同步 异