【C/C++服务器开发】同步与异步、阻塞与非阻塞、同步调用和异步调用的概念

2023-05-16

同步与异步

首先我们要明确的是,同步和异步都是针对两个或者两个以上的事物来说的。比如当我们在网上购物看中一件物品,然后去浏览该商品详情的时候,首先页面会先发送一个请求,后台服务器查询对应商品的相关数据,然后前端详情页面才根据返回数据展示该商品的详细信息。而此时你的网速比较差,一个详情页面等了将近一分钟才全部展示完成,这时候你问这个请求是同步还是异步?答案显然是同步请求,它给我们最直观的表现形式就是页面一直显示在加载中,商品的详情页面渲染必须要等待后台服务器返回商品详情数据后才能进行。也就是说下一个操作必须要等待上一个操作完成才能进行,它依赖于上一个操作的返回结果。

你可能会问,在同步的情况下,当一个事物正在进行操作的时候,其它的事物此时在干嘛呢?这个实际上并没有明确的规定,其实同步更多的是关注事物一个一个的串行执行的过程,保证不会交叉执行,至于某个时刻处于什么状态并不关心。这在计算机中大部分时候其它事物都是处于一个等待的状态,而我们人则要灵活得多,在我们日常生活中常用的同步手段就是排队,比如我们上下班坐地铁进行安检的时候,需要依次排队安检进站乘车,但是你在排队的过程是在看手机、聊天还是什么也不做都可以,安检人员并不会在意你在做什么,这种就是由于安检资源有限导致的同步。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-60PQa7Bc-1637423876603)(https://segmentfault.com/img/remote/1460000022478669)]

对于同步这里有两个点需要注意,一是同步的范围,有时候并不需要全局的大范围的去同步,只需要在特定的操作同步即可,这样可以提升执行效率,比如 Java 语言中的同步方法和同步代码块。另一个是同步的粒度,并不是在一些大的操作粒度上才需要同步操作,小的粒度操作也需要同步操作,只是有的小粒度操作天然就已经是同步操作,并不需要我们人为的去添加同步操作控制。比如 Java 语言中的同步都是针对有两个或者两个以上线程的程序来说的,因为单线程的程序里它天然就是同步的。
异步则完全相反,在异步情况下多个事务可以同时进行,互不影响,你进行你的,我进行我的,谁都不用关心谁。总的来说就是:

  • 同步 两个事物相互依赖,并且一个事物必须以依赖于另一事物的执行结果。比如在事物 A->B 事件模型中,你需要先完成事物 A 才能执行事物 B。也就是说,同步调用在被调用者未处理完请求之前,调用不返回,调用者会一直等待结果的返回。
  • 异步 两个事物完全独立,一个事物的执行不需要等待另外一个事物的执行。也就是说,异步调用可以返回结果不需要等待结果返回,当结果返回的时候通过回调函数或者其他方式带着调用结果再做相关事情。

可以看出同步与异步是从行为角度描述事物的,你品,你细品。(PS:这里的多个事务可以指代不同的操作、不同的方法或者不同的代码语句等等

阻塞与非阻塞

所谓阻塞,简单来说就是发出一个请求不能立刻返回响应,要等所有的逻辑全处理完才能返回响应。非阻塞反之,发出一个请求立刻返回应答,不用等处理完所有逻辑。阻塞与非阻塞指的是单个线程内遇到同步等待时,是否在原地不做任何操作。
堵车就是阻塞与非阻塞最好的例子,在一线城市生活过的朋友应该都有体会,在交通正常的时候汽车可以正常通行,就是非阻塞,上下班高峰的时候经常发生堵车,交通正常的时候半个小时车程,高峰期可能需要二、三个小时才能到。。。而且一旦发生交通堵塞,所有马路上的车子都一动不动,只能在车子里等待,就是阻塞,当然大多数人不会选择干等,他们会玩手机或者和朋友聊天等等,同样的在计算机里,阻塞就意味着停止执行停下来等待,非阻塞表明操作可以继续向下执行,但是在发生阻塞的时候计算机可就没有像人这么灵活了,通常计算机的处理方式就是挂起当前线程,然后干等着,阻塞结束后才继续执行该线程。可以看出阻塞和非阻塞描述的当前事物的状态(等待调用结果时的状态)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vysvLOAu-1637423876605)(https://segmentfault.com/img/remote/1460000022478670)]

结合前面介绍的同步与异步,两两组合就会有四种情况,分别是同步阻塞同步非阻塞异步阻塞异步非阻塞。下面通过车道的例子来形象的解释这几种状态:

  • 同步阻塞 只有一个车道,不能超车,所有车子依次行使,一次只能通过一辆车,尴尬的是这个车道还堵车了。
  • 同步非阻塞 只有一个车道,不能超车,所有车子依次行使,一次只能通过一辆车,不过比较幸运这个车道没有堵车,可以正常通行。
  • 异步阻塞 有两个或两个以上车道,每条马路都可以通行,不同车道上的车子可以并行行使,尴尬的是所有的车道都堵车了。
  • 异步非阻塞 有两个或两个以上车道,每条马路都可以通行,不同车道上的车子可以并行行使,不过比较幸运的是没有一个车道堵车,都可以正常通行。

对应到我们计算机里也是一样的,同步阻塞相当于只有一个线程,而且该线程处于阻塞(Blocked)状态,同步非阻塞相当于只有一个线程,而且该线程处于运行(Running)状态。异步阻塞相当于有多个线程,而且所有线程都处于阻塞(Blocked)状态,异步非阻塞相当于有多个线程,而且所有线程都在正常运行。

同步调用和异步调用

同步和异步主要用于修饰方法。当一个方法被调用时,调用者需要等待该方法执行完毕并返回才能继续执行,我们称这个方法是同步方法;当一个方法被调用时立即返回,并获取一个线程执行该方法内部的业务,调用者不用等待该方法执行完毕,我们称这个方法为异步方法。异步的好处在于非阻塞(调用线程不会暂停执行去等待子线程完成),因此我们把一些不需要立即使用结果、较耗时的任务设为异步执行,可以提高程序的运行效率。

同步调用是以一种阻塞式调用

比如说:古代的长城的烽火传递信息,现在我们假设每个烽火只能看到相邻的烽火状态,每个烽火的状态只有亮和暗。

现在有A、B、C、D四个烽火,A首先点亮,B看到A的烽火亮了,立马去点火,花了2秒点亮。但是这时候负责C烽火的人在睡觉,可是这时候所有人都在等待C点亮,终于C睡了2个小时候看到了B点亮,然后去点亮。D由于长期没有点亮,导致烽火出现问题,因此整个过程都在等待D的完成。这种就是典型的阻塞机制,无论如何我们只能等待上一个任务的完成,如果没有完成我们只能继续等待,这样造成的问题是,我们一直在浪费系统资源。

异步调用

异步调用是一种类似消息或事件的机制,不过它的调用方向刚好相反,接口的服务在收到某种讯息或发生某种事件时,会主动通知客户方(即调用客户方的接口)。

依然是上面的例子:

现在我们有一个将臣F,他专门负责告诉每个烽火需要去点亮

A、B、C、D四个烽火,将臣先告诉了A,然后不等A点亮,他继续告诉了B、C和D。最后A在2小时后告诉了F我完成了,B在1小时后告诉了F我完成了,C在1.5小时后告诉F完成了,而D在3小时后告诉F完成了。F收到这些信息后,才知道整个过程完成了。

socket缓冲区以及阻塞模式详解

以socket这边的情况来理解一下阻塞模式。

socket缓冲区

每个 socket 被创建后,都会分配两个缓冲区,输入缓冲区和输出缓冲区。

write()/send() 并不立即向网络中传输数据,而是先将数据写入缓冲区中,再由TCP协议将数据从缓冲区发送到目标机器。一旦将数据写入到缓冲区,函数就可以成功返回,不管它们有没有到达目标机器,也不管它们何时被发送到网络,这些都是TCP协议负责的事情。

TCP协议独立于 write()/send() 函数,数据有可能刚被写入缓冲区就发送到网络,也可能在缓冲区中不断积压,多次写入的数据被一次性发送到网络,这取决于当时的网络情况、当前线程是否空闲等诸多因素,不由程序员控制。

read()/recv() 函数也是如此,也从输入缓冲区中读取数据,而不是直接从网络中读取。

TCP套接字的I/O缓冲区示意图
图:TCP套接字的I/O缓冲区示意图

这些I/O缓冲区特性可整理如下:

  • I/O缓冲区在每个TCP套接字中单独存在;
  • I/O缓冲区在创建套接字时自动生成;
  • 即使关闭套接字也会继续传送输出缓冲区中遗留的数据;
  • 关闭套接字将丢失输入缓冲区中的数据。

输入输出缓冲区的默认大小一般都是 8K,可以通过 getsockopt() 函数获取:

unsigned optVal;
int optLen = sizeof(int);
getsockopt(servSock, SOL_SOCKET, SO_SNDBUF, (char*)&optVal, &optLen);
printf("Buffer length: %d\n", optVal);

运行结果:
Buffer length: 8192

这里仅给出示例,后面会详细讲解。

阻塞模式

对于TCP套接字(默认情况下),当使用 write()/send() 发送数据时:

  1. 首先会检查缓冲区,如果缓冲区的可用空间长度小于要发送的数据,那么 write()/send() 会被阻塞(暂停执行),直到缓冲区中的数据被发送到目标机器,腾出足够的空间,才唤醒 write()/send() 函数继续写入数据。

  2. 如果TCP协议正在向网络发送数据,那么输出缓冲区会被锁定,不允许写入,write()/send() 也会被阻塞,直到数据发送完毕缓冲区解锁,write()/send() 才会被唤醒。

  3. 如果要写入的数据大于缓冲区的最大长度,那么将分批写入。

  4. 直到所有数据被写入缓冲区 write()/send() 才能返回。

当使用 read()/recv() 读取数据时:

  1. 首先会检查缓冲区,如果缓冲区中有数据,那么就读取,否则函数会被阻塞,直到网络上有数据到来。

  2. 如果要读取的数据长度小于缓冲区中的数据长度,那么就不能一次性将缓冲区中的所有数据读出,剩余数据将不断积压,直到有 read()/recv() 函数再次读取。

  3. 直到读取到数据后 read()/recv() 函数才会返回,否则就一直被阻塞。

这就是TCP套接字的阻塞模式。所谓阻塞,就是上一步动作没有完成,下一步动作将暂停,直到上一步动作完成后才能继续,以保持同步性。

TCP套接字默认情况下是阻塞模式,也是最常用的。当然你也可以更改为非阻塞模式,后续我们会讲解。

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

【C/C++服务器开发】同步与异步、阻塞与非阻塞、同步调用和异步调用的概念 的相关文章

  • 【LeetCode刷题日记】[413. 等差数列划分]

    LeetCode刷题日记 413 等差数列划分 题目描述 如果一个数列 至少有三个元素 xff0c 并且任意两个相邻元素之差相同 xff0c 则称该数列为等差数列 例如 xff0c 1 3 5 7 9 7 7 7 7 和 3 1 5 9 都
  • boost初探-日期与时间

    文章目录 一 前言二 boost基本概念三 日期与时间1 timer2 progress timer3 data time库3 1gregorian3 2date period 4 posix time 一 前言 之前写了两篇关于在linu
  • Runtime(运行时)是什么意思

    什么是 runtime 在计算机领域中 xff0c 经常会接触到 runtime 这个概念 xff0c 那么 runtime 究竟是什么东西 xff1f runtime 描述了程序运行时候执行的软件 指令 xff0c 在每种语言有着不同的实
  • 【C/C++开源库】C/C++矩阵运算开源库

    文章目录 一 C 43 43 矩阵运算库 eigen1 下载及安装1 1Linux安装及配置1 2Windows配置 2 测试使用2 1DevC 43 43 2 2Clion 3 深入学习 二 C 43 43 矩阵运算库 Armadillo
  • Cannot resolve plugin org.apache.maven.plugins:maven-resources-plugin:3.2.0

    一 概述 过了个周末回来更新代码之后 xff0c 重新built之后 xff0c 竟然built失败了 xff0c 提示信息为 xff1a Cannot resolve plugin org apache maven plugins mav
  • 并行计算之OpenMP入门简介

    转载于 xff1a https www cnblogs com kuliuheng p 4059133 html OpenMp提供了对于并行描述的高层抽象 xff0c 降低了并行编程的难度和复杂度 xff0c 这样程序员可以把更多的精力投入
  • PHP + Apache + Mysql集成环境部署及简要教程

    文章目录 PHP运行原理和机制PHP 的设计理念及特点PHP 的四层体系1 Zend 引擎 xff08 核心 xff09 2 Extensions xff08 扩展 xff09 3 SAPI xff08 服务器应用程序编程接口 xff09
  • 不同行业公司工资对比,计算机YYDS

    一 纳税标准 推荐一篇文章 xff1a 扣除社保 公积金年后 社保和公积金的扣除比例是22 左右 xff0c 工资在扣完社保和公积金的基础上再进行个税的扣除 税前19 2w xff0c 税前平均每月1 6w xff0c 扣除社保 公积金后年
  • 对实时操作系统多任务的一些理解

    一 什么是优先级反转 优先级反转 xff0c 是指在使用信号量时 xff0c 可能会出现的这样一种不合理的现象 xff0c 即 xff1a 优先级反转是指一个低优先级的任务持有一个被高优先级任务所需要的共享资源 高优先任务由于因资源缺乏而处
  • 【LeetCode刷题日记】数组和链表性质总结

    一 数据结构的存储方式 数据结构的存储方式只有两种 xff1a 数组 xff08 顺序存储 xff09 和链表 xff08 链式存储 xff09 这句话怎么理解 xff0c 不是还有散列表 栈 队列 堆 树 图等等各种数据结构吗 xff1f
  • C语言面向对象实现滑动均值滤波与平均值滤波

    文章目录 一 背景二 平均值滤波1 算法介绍2 代码实现3 实例 三 滑动均值滤波 xff08 Moving Average xff09 四 C语言面向面向对象实现滑动均值滤波 一 背景 在实际的数据采集中 xff0c 我们经常会取多次数据
  • 【LeetCode刷题日记】常用算法基础和理解及运用

    在我们LeetCode刷题过程中 xff0c 如果我们只是了解数据结构 xff08 数组 xff0c 链表 xff0c 数 xff09 的使用方法 xff0c 那我们在面对复杂的题目时 xff0c 是很难很好的解决问题的 xff0c 因此我
  • 【LeetCode刷题日记】数组类题目常见题型

    文章目录 303 区域和检索 数组不可变 https leetcode cn com problems range sum query immutable 304 二维区域和检索 矩阵不可变 https leetcode cn com pr
  • 【LeetCode刷题日记】队列类题目常见题型

    文章目录 225 用队列实现栈 https leetcode cn com problems implement stack using queues 剑指 Offer 09 用两个栈实现队列 https leetcode cn com p
  • 【LeetCode刷题日记】栈类题目常见题型

    文章目录 20 有效的括号 https leetcode cn com problems valid parentheses 225 用队列实现栈 https leetcode cn com problems implement stack
  • 回顾 nexus maven-snapshots 401 Unauthorized

    1 修改maven settings 文件 私库的用户名和密码 lt server gt lt id gt maven releases lt id gt lt username gt admin lt username gt lt pas
  • 【LeetCode刷题日记】树类题目常见题型

    文章目录 树基础知识 104 二叉树的最大深度 https leetcode cn com problems maximum depth of binary tree 102 二叉树的层序遍历 https leetcode cn com p
  • 【LeetCode刷题日记】常用算法基础和理解及运用

    文章目录 递归和迭代递归迭代迭代和递归的关系和区别 xff08 敲黑板 xff09 二分法典型的二分法二分法的变种找出第一个与key相等的元素的位置找出最后一个与key相等的元素的位置查找第一个等于或者大于Key的元素的位置查找第一个大于k
  • 编程常用快捷键,学完保证和大神一样件字如飞

    每次看到一下大神在编程时 xff0c 那打字的速度简直是恐怖 xff0c 而且几乎不会用到鼠标 xff0c 手不用离开键盘 xff0c 因此打字效率也高 而菜鸡的我 xff0c 每次写代码时 xff0c 有时候要在不同行之间跳动 xff0c
  • Clion中编译C/C++混合代码

    今天在Clion中编译C C 43 43 语言时 xff0c 出现了一个不容易发现的错误 项目文件包括三个文件 三个文件其实都是用C语言写的 xff0c 只是第一个文件的后缀是 cpp 如果在这种情况下直接编译 xff0c 会出现一下报错

随机推荐

  • 【LeetCode刷题日记】[447. 回旋镖的数量](https://leetcode-cn.com/problems/number-of-boomerangs/)

    LeetCode刷题日记 447 回旋镖的数量 题目 给定平面上 n 对 互不相同 的点 points xff0c 其中 points i 61 xi yi 回旋镖 是由点 i j k 表示的元组 xff0c 其中 i 和 j 之间的距离和
  • 【LeetCode刷题日记】[162. 寻找峰值]

    LeetCode刷题日记 162 寻找峰值 题目 峰值元素是指其值严格大于左右相邻值的元素 给你一个整数数组 nums xff0c 找到峰值元素并返回其索引 数组可能包含多个峰值 xff0c 在这种情况下 xff0c 返回 任何一个峰值 所
  • 基于Junit4+Mockito+PowerMock实现Controller+Service的单元测试

    一 导入的依赖 lt test gt lt dependency gt lt groupId gt org mockito lt groupId gt lt artifactId gt mockito core lt artifactId
  • 嵌入式编程之状态机

    文章目录 1 什么是状态机 xff1f 2 状态机编程的优点 1 提高CPU使用效率 2 逻辑完备性 3 程序结构清晰 3 状态机的三种实现方法switch case 法表格驱动法函数指针法小节 摘要 xff1a 不知道大家有没有这样一种感
  • VxWorks几种常用的延时方法

    转载于 xff1a https www vxworks net app 144 time facilities of vxworks 自用 VxWorks系统提供灵活多样的定时器机制 xff0c 有多种接口可以方便地实现延时 xff0c 文
  • 推荐一些嵌入式、C/C++的开源库和项目

    前言 想用代码实现一个功能时 xff0c 我们可以先看看是否有前辈已经实现了该功能 xff0c 并且开源分享在网上 一般我们自己造出来的轮子的可用性基本上是很难和大神们造的轮子相比的 因此多了解一下优秀的开源库的使用 xff0c 可以让我们
  • 对于LSB的理解(位的LSB、模数转换的LSB)

    之前对于LSB的理解 xff1a 最高有效位 xff08 MSB xff09 指二进制中最高值的比特 在16比特的数字音频中 xff0c 其第1个比特便对16bit的字的数值有最大的影响 例如 xff0c 在十进制的15389这一数字中 x
  • C语言跳转语句(break语句,continue语句,goto语句,return语句,跳转函数setjmp和longjmp)

    文章目录 一 前言二 跳转语句1 break 语句2 continue 语句3 goto 语句4 return 语句 三 跳转函数1 C标准库 一 前言 跳转语句 xff08 jump statement xff09 可以中断当前程序的执行
  • C 语言跳转表的实现及在嵌入式设备中的应用

    转载于https cloud tencent com developer article 1797595 跳转表的概念 引用笔者在 Wikipedia 上看到的关于跳转表的概念 xff0c In computer programming a
  • 软件版本控制,软件推荐及使用教程

    文章目录 一 版本控制系统分类1 版本控制系统的概念2 本地版本控制系统 3 集中式版本控制系统 4 分布式版本控制系统 Git 二 版本控制软件使用简明教程1 集中式版本控制系统 SVN2 分布式版本控制系统 把文件添加到版本库 工作区
  • 串口通信库总结

    C 43 43 开源库 Windows和linux下好用的串口通讯API库 serial 在 C 43 43 xff0c 跨平台 xff0c 串口库编写 https github com wjwwood serial boost网络串口通信
  • 【C语言开源库】lw_oopc:轻量级的C语言面向对象编程框架

    文章目录 轻量级的面向对象C语言编程框架LW OOPC介绍摘要s为什么要用面向对象 为什么不直接使用C 43 43 LW OOPC是什么 LW OOPC宏介绍问题描述解决方案方案的可扩展性如何 LW OOPC最佳实践LW OOPC的优点LW
  • Go语言基础语法入门

    一 下载及安装 被河蟹了 xff01 xff01 xff01 二 入门教程 Go 语言结构 在我们开始学习 Go 编程语言的基础构建模块前 xff0c 让我们先来了解 Go 语言最简单程序的结构 Go Hello World 实例 Go 语
  • docker环境安装tomcat

    一 安装tomcat 1 查找tomcat镜像 docker search tomcat 2 安装指定版本的tomcat镜像 docker pull tomcat 9 0 二 启动tomcat镜像 docker run d p 8080 8
  • Go语言并发详解

    文章目录 一 Go语言并发简述 xff08 并发的优势 xff09 进程 线程并发 并行协程 线程Goroutine 介绍channel 二 Go语言goroutine xff08 轻量级线程 xff09 使用普通函数创建 goroutin
  • C/C++ 服务器/后台开发学习路线总结及准备

    文章目录 一 前言二 总结网上的学习路线三 之前的一些相关博客整理 一 前言 最近要新开一个非常重要的系列 xff0c C C 43 43 服务器 后台开发 这个系列将会包括非常多的内容 xff0c 难度也会比之前的系列大很多 xff0c
  • 学了十几种编程语言后,我有哪些感受?

    转一下鱼皮大佬的文章 xff1a https mp weixin qq com s Eier53 flKEtxj yGIQs8A 大家好 xff0c 我是鱼皮 学编程 5 年多了 xff0c 我学过十几种编程语言 xff0c 比如 C C
  • 【C/C++服务器开发】什么是服务器?服务器分类及构建一个简单的服务器系统

    文章目录 一 服务器的定义二 服务器的分类1 外形2 CPU指令集3 用途1 web服务器WEB简介协议WWW简介发展和特点服务器特点工作原理 2 应用服务器定义分类静态动态 概括区别应用服务器和WEB服务器的区别Web型应用程序型 3 文
  • 函数式编程初探及Haskell简介

    诞生50多年之后 xff0c 函数式编程 xff08 functional programming xff09 开始获得越来越多的关注 不仅最古老的函数式语言Lisp重获青春 xff0c 而且新的函数式语言层出不穷 xff0c 比如Erla
  • 【C/C++服务器开发】同步与异步、阻塞与非阻塞、同步调用和异步调用的概念

    同步与异步 首先我们要明确的是 xff0c 同步和异步都是针对两个或者两个以上的事物来说的 比如当我们在网上购物看中一件物品 xff0c 然后去浏览该商品详情的时候 xff0c 首先页面会先发送一个请求 xff0c 后台服务器查询对应商品的