C++面试速通宝典——25

news2024/11/24 15:44:51

473. HTTP如何减少重定向请求

重定向请求

‌‌‌‌  服务器上的一个资源可能由于迁移、维护等原因从url1移至url2后,而客户端不知情,他还是继续请求url1,这时服务器不能粗暴地返回错误,而是通过302响应码和Location头部,告诉客户端该资源已经迁移至url2了,于是客户端需要再次发送url2请求以获得服务器的资源。
‌‌‌‌  那么,如果重定向请求越多,那么客户端就要多次发起HTTP请求,每一次得HTTP请求都得经过网络,这无疑会越降低网络性能。
‌‌‌‌  另外,服务器端这一方往往不只有一台服务器。比如源服务器上一级是代理服务器,然后代理服务器才与客户端通信,这时客户端重定向就会导致客户端与代理服务器之间需要2次消息传递。
在这里插入图片描述

如果重定向的工作交由代理服务器完成,就能减少HTTP请求次数了。
在这里插入图片描述

而且当代理服务器知晓了重定向规则后,可以进一步减少消息传递次数。
![[images/Pasted image 20240823123151.png]]

474. HTTP与WebSocket

  1. 全双工和半双工:TCP协议本身是全双工的,但我们最常用的HTTP/1.1,虽然是基于TCP的协议,但他是半双工的,对于大部分需要服务器主动推送数据到客户端的场景,都不太友好,因此我们需要使用支持全双工的WebSocket协议。
  2. 应用场景区别:在HTTP/1.1里,只要客户端不问,服务端就不答。基于这样的特点,对于登录页面这样的简单场景,可以使用定时轮询或者长轮询的方式实现服务器推送的效果。对于客户端和服务器端之间需要频繁交互的复杂场景,比如网页游戏,都可以考虑WebSocket协议。

475. 怎么建立WebSocket连接

  1. 客户端请求连接:客户端(如浏览器或应用程序)通过WebSocket API像服务器发送连接请求,这通常包含一个特殊的HTTP请求(握手请求),请求头中包含必要的WebSocket信息。
  2. 服务器响应确认:服务器收到连接请求后,检查请求的有效性。如果请求合法,服务器会回复一个HTTP 101状态码,表示协议切换成功。此时,HTTP连接升级为WebSocket连接。
  3. 建立双向通信:一旦连接建立,客户端和服务器之间可以开始双向通信。双方都可以随时发送和接收消息,直到连接关闭。
  4. 监听和处理事件:在连接期间,双方应当能够处理连接事件(如打开、关闭和错误),以确保通信的稳定性和可靠性。
  5. 关闭连接:任何一方都可以主动关闭连接,通常通过发送关闭帧的方式。连接关闭后,双方不再能够通过该连接发送消息。

476. 如何实现扫码请求?

‌‌‌‌  可以使用长轮询的方案,比如将HTTP请求将超时设置的很大,比如30s,在这30s内只要服务器收到了扫码请求,就立马返回给客户端网页。如果超时,那就立马发起下一次请求

‌‌‌‌  这样就减少了HTTP请求的个数,并且由于大部分情况下,用户都会在某个30s的区间内做扫码操作,所以响应也是及时的。

比如,某度云网盘就是这么做的,所以你会发现一扫码,手机上点个确认,电脑端网页就秒跳转,体验很好。
在这里插入图片描述
在这里插入图片描述

477. CPU如何读取内存

‌‌‌‌  我们第一个要搞清楚的问题是:谁来告诉CPU去读写内存?

‌‌‌‌  答案很明显,是程序员更具体的是编译器

‌‌‌‌  CPU只是按照指令按部就班的执行,机器指令从哪里来的呢?是编译器生成的,程序员通过高级语言编写程序,编译器将其翻译为机器指令,机器指令来告诉CPU去读写内存

‌‌‌‌  在精简指令集架构下会有特定的机器指令,Load/Store指令来读写内存,以x86为代表的复杂指令集架构下没有特定的访存指令。

‌‌‌‌  精简指令集下,一条机器指令操作的数据必须来存放在寄存器中,不能直接操作内存数据,因此RISC下,数据必须先从内存搬运到寄存器,这就是为什么RISC下会有特定的Load/Store访存指令,明白了吧。

‌‌‌‌  而x86下无此限制,一条机器指令操作的数据可以来自于寄存器也可以来自内存,因此这样一条机器指令在执行过程中会首先从内存中读取数据。

‌‌‌‌  现在我们知道了,是特定的机器指令告诉CPU要去访问内存。

‌‌‌‌  不过,值得注意的是,不管是RISC下特定的Load/Store指令还是x86下包含在一条指令内部的访存操作,这里读写的都是内存中的数据,除此之外还要意识到,CPU除了从内存中读写数据外,还要从内存中读取下一条要执行的机器指令

‌‌‌‌  毕竟,我们的计算设备都遵从冯诺依曼架构:程序和数据一视同仁,都可以存放在内存中
![[images/Pasted image 20240823163524.png]]

现在,我们清楚了CPU读写内存其实是由两个因素来驱动的:

  1. 程序执行过程中需要读写来自内存中的数据

  2. CPU需要访问内存读取下一条要执行的机器指令

‌‌‌‌  然后CPU根据机器指令中包含的内存地址或者PC寄存器中下一条机器指令的地址访问内存。

‌‌‌‌  这不就完了吗?有了内存地址,CPU利用硬件通路直接读内存就好了,你可能也是这样的想的。

‌‌‌‌  真的是这样吗?别着急,我们接着往下看,这两节只是开胃菜,正餐才刚刚开始。

‌‌‌‌  假设你是一个整天无所事事的吃货,整天无所事事,唯一的爱好就是找一家餐厅吃吃喝喝,由于你是职业吃货,因此吃起来非常职业,1分钟就能吃完一道菜,但这里的厨师就没有那么职业了,炒一道菜速度非常慢,大概需要1小时40分钟才能炒出一道菜,速度比你慢了100倍,如果你是这个吃货,大概率会疯掉的。

‌‌‌‌  而CPU恰好就是这样一个吃货,内存就是这样一个慢吞吞的厨师,而且随着时间的推移这两者的速度差异正在越来越
在这里插入图片描述

‌‌‌‌  在这种速度差异下,CPU执行一条涉及内存读写指令时需要等“很长一段时间”数据才能“缓缓的”从内存读取到CPU中,在这种情况你还认为CPU应该直接读写内存吗?

‌‌‌‌  CPU执行指令符合28定律,大部分时间都在执行那一少部分指令,这一现象的发现奠定了精简指令集设计的基础。

‌‌‌‌  而程序操作的数据也符合类似的定律,只不过不叫28定律,而是叫principle of locality,程序局部性原理

‌‌‌‌  如果我们访问内存中的一个数据A,那么很有可能接下来再次访问到,同时还很有可能访问与数据A相邻的数据B,这分别叫做时间局部性空间局部性
在这里插入图片描述

‌‌‌‌  如图所示,该程序占据的内存空间只有一少部分在程序执行过程经常用到

‌‌‌‌  有了这个发现重点就来了,既然只用到很少一部分,那么我们能不能把它们集中起来呢?就像这样:
在这里插入图片描述

‌‌‌‌  集中起来然后呢?放到哪里呢?

‌‌‌‌  当然是放到一种比内存速度更快的存储介质上,这种介质就是我们熟悉的SRAM,普通内存一般是DRAM,这种读写速度更快的介质充当CPU和内存之间的Cache,这就是所谓的缓存

‌‌‌‌  我们把经常用到的数据放到cache中存储,CPU访问内存时首先查找cache,如果能找到,也就是命中,那么就赚到了,直接返回即可,找不到再去查找内存并更新cache。

‌‌‌‌  我们可以看到,有了cache,CPU不再直接与内存打交道了
在这里插入图片描述

‌‌‌‌  但cache的快速读写能力是有代价的,代价就是Money,造价不菲,因此我们不能把内存完全替换成cache的SRAM,那样的计算机你我都是买不起的

‌‌‌‌  因此cache的容量不会很大,但由于程序局部性原理,因此很小的cache也能有很高的命中率,从而带来性能的极大提升,有个词叫四两拨千斤,用到cache这里再合适不过。

‌‌‌‌  虽然小小的cache能带来性能的极大提升,但,这也是有代价的。

‌‌‌‌  这个代价出现在写内存时。

‌‌‌‌  当CPU需要写内存时该怎么办呢?

‌‌‌‌  现在有了cache,CPU不再直接与内存打交道,因此CPU直接写cache,但此时就会有一个问题,那就是cache中的值更新了,但内存中的值还是旧的,这就是所谓的不一致问题,inconsistent.

‌‌‌‌  就像下图这样,cache中变量的值是4,但内存中的值是2。
在这里插入图片描述

‌‌‌‌  常用 redis 的同学应该很熟悉这个问题,可是你知道吗?这个问题早就在你读这篇文章用的计算设备其包含的CPU中已经遇到并已经解决了。

‌‌‌‌  最简单的方法是这样的,当我们更新cache时一并把内存也更新了,这种方法被称为 write-through,很形象吧。

‌‌‌‌  可是如果当CPU写cache时,cache中没有相应的内存数据该怎么呢?这就有点麻烦了,首先我们需要把该数据从内存加载到cache中,然后更新cache,再然后更新内存。
在这里插入图片描述

‌‌‌‌  这种实现方法虽然简单,但有一个问题,那就是性能问题,在这种方案下写内存就不得不访问内存,上文也提到过CPU和内存可是有很大的速度差异哦,因此这种方案性能比较差。

有办法解决吗?答案是肯定的。

这种方法性能差不是因为写内存慢,写内存确实是慢,更重要的原因是CPU在同步等待,因此很自然的,这类问题的统一解法就是把同步改为异步。

关于同步和异步的话题,你可以参考这篇文章《从小白到高手,你需要理解同步和异步》。

异步的这种方法是这样的,当CPU写内存时,直接更新cache,然后,注意,更新完cache后CPU就可以认为写内存的操作已经完成了,尽管此时内存中保存的还是旧数据。

当包含该数据的cache块被剔除时再更新到内存中,这样CPU更新cache与更新内存就解耦了,也就是说,CPU更新cache后不再等待内存更新,这就是异步,这种方案也被称之为write-back,这种方案相比write-through来说更复杂,但很显然,性能会更好。
在这里插入图片描述

‌‌‌‌  现在你应该能看到,添加cache后会带来一系列问题,更不用说cache的替换算法,毕竟cache的容量有限,当cache已满时,增加一项新的数据就要剔除一项旧的数据,那么该剔除谁就是一个非常关键的问题,限于篇幅就不在这里详细讲述了,你可以参考《深入理解操作系统》第7章有关于该策略的讲解。

‌‌‌‌  现代CPU为了增加CPU读写内存性能,已经在CPU和内存之间增加了多级cache,典型的有三级,L1、L2和L3,CPU读内存时首先从L1 cache找起,能找到直接返回,否则就要在L2 cache中找,L2 cache中找不到就要到L3 cache中找,还找不到就不得不访问内存了。

因此我们可以看到,现代计算机系统CPU和内存之间其实是有一个cache的层级结构的
在这里插入图片描述

越往上,存储介质速度越快,造价越高容量也越小;越往下,存储介质速度越慢,造价越低但容量也越大。

现代操作系统巧妙的利用cache,以最小的代价获得了最大的性能。

但是,注意这里的但是,要想获得极致性能是有前提的,那就是程序员写的程序必须具有良好的局部性,充分利用缓存

高性能程序在充分利用缓存这一环节可谓绞尽脑汁煞费苦心,关于这一话题值得单独成篇,关注公众号“码农的荒岛求生”,并回复“todo”,你可以看到之前所有挖坑的进展如何

鉴于cache的重要性,现在增大cache已经成为提升CPU性能的重要因素,因此你去看当今的CPU布局,其很大一部分面积都用在了cache上。
在这里插入图片描述

当摩尔定律渐渐失效后鸡贼的人类换了另一种提高CPU性能的方法,既然单个CPU性能不好提升了,我们还可以堆数量啊,这样,CPU进入多核时代,程序员开始进入苦逼时代。

拥有一堆核心的CPU其实是没什么用的,关键需要有配套的多线程程序才能真正发挥多核的威力,但写过多线程程序的程序员都知道,能写出来不容易,能写出来并且能正确运行更不容易,关于多线程与多线程编程的详细阐述请参见《深入理解操作系统》第5、6两章(关注公众号“码农的荒岛求生”并回复“操作系统”)。

CPU开始拥有多个核心后不但苦逼了软件工程师,硬件工程师也不能幸免。

前文提到过,为提高CPU 访存性能,CPU和内存之间会有一个层cache,但当CPU有多个核心后新的问题来了:
在这里插入图片描述

‌‌‌‌  现在假设内存中有一变量X,初始值为2。

‌‌‌‌  系统中有两个CPU核心C1和C2,现在C1和C2要分别读取内存中X的值,根据cache的工作原理,首次读取X不能命中cache,因此从内存中读取到X后更新相应的cache,现在C1 cache和C2 cache中都有变量X了,其值都是2。

‌‌‌‌  接下来C1需要对X执行+2操作,同样根据cache的工作原理,C1从cache中拿到X的值+2后更新cache,在然后更新内存,此时C1 cache和内存中的X值都变为了4。
然后C2也许需要对X执行加法操作,假设需要+4,同样根据cache的工作原理,C2从cache中拿到X的值+4后更新cache,此时cache中的值变为了6(2+4),再更新内存,此时C2 cache和内存中的X值都变为了6。
在这里插入图片描述
在这里插入图片描述

‌‌‌‌  一个初始值为2的变量,在分别+2和+4后正确的结果应该是2+2+4 = 8,但从上图可以看出内存中X的值却为6,问题出在哪了呢?
‌‌‌‌  有的同学可能已经发现了,问题出在了内存中一个X变量在C1和C2的cache中有共计两个副本,当C1更新cache时没有同步修改C2 cache中X的值

在这里插入图片描述

解决方法是什么呢?

‌‌‌‌  显然,如果一个cache中待更新的变量同样存在于其它核心的cache,那么你需要一并将其它cache也更新好。

‌‌‌‌  现在你应该看到,CPU更新变量时不再简单的只关心自己的cache和内存,你还需要知道这个变量是不是同样存在于其它核心中的cache,如果存在需要一并更新。

‌‌‌‌  当然,这还只是简单的读,写就更加复杂了,实际上,现代CPU中有一套协议来专门维护缓存的一致性,比较经典的包括MESI协议等。

‌‌‌‌  为什么程序员需要关心这个问题呢?原因很简单,你最好写出对cache一致性协议友好的程序因为cache频繁维护一致性也是有性能代价的

怎么样?到目前为止,是不是CPU读写内存没有看上去那么简单?

现代计算机中CPU和内存之间有多级cache,CPU读写内存时不但要维护cache和内存的一致性,同样需要维护多核间cache的一致性

‌‌‌‌  现代程序员写程序基本上不需要关心内存是不是足够这个问题,但这个问题在远古时代绝对是困扰程序员的一大难题。

‌‌‌‌  如果你去想一想,其实现代计算机内存也没有足够大的让我们随便申请的地步,但是你在写程序时是不是基本上没有考虑过内存不足该怎么办?
‌‌‌‌  
‌‌‌‌  为什么我们在内存资源依然处于匮乏的现代可以做到申请内存时却进入内存极大丰富的共产主义理想社会了呢?

‌‌‌‌  原来这背后的功臣是我们熟悉的操作系统

‌‌‌‌  操作系统对每个进程都维护一个假象,即,每个进程独占系统内存资源;同时给程序员一个承诺,让程序员可以认为在写程序时有一大块连续的内存可以使用。

‌‌‌‌  这当然是不可能不现实的,因此操作系统给进程的地址空间必然不是真的,但我们又不好将其称之为“假的地址空间”,这会让人误以为计算机科学界里骗子横行,因此就换了一个好听的名字,虚拟内存,一个“假的地址空间”更高级的叫法。

‌‌‌‌  进程其实一直活在操作系统精心维护的幻觉当中,就像《盗梦空间》一样。

‌‌‌‌  CPU真的是很傻很天真的存在。

‌‌‌‌  上一节讲的操作系统施加的障眼法把CPU也蒙在鼓里。

‌‌‌‌  CPU执行机器指令时,指令指示CPU从内存地址A中取出数据,然后CPU执行机器指令时下发命令:“给我从地址A中取出数据”,尽管真的能从地址A中取出数据,但这个地址A不是真的,不是真的,不是真的。

‌‌‌‌  因为这个地址A属于虚拟内存,也就是那个“假的地址空间”,现代CPU内部有一个叫做MMU的模块将这假的地址A转换为真的地址B,将地址A转换为真实的地址B之后才是本文之前讲述的关于cache的那一部分。
在这里插入图片描述

‌‌‌‌  CPU给出内存地址,此后该地址被转为真正的物理内存地址,接下来查L1 cache,L1 cache不命中查L2 cache,L2 cache不命中查L3 cache,L3 cache不能命中查内存。

‌‌‌‌  各单位注意,各单位注意,到查内存时还不算完,现在有了虚拟内存,内存其实也是一层cache,是磁盘的cache,也就是说查内存也有可能不会命中,因为内存中的数据可能被虚拟内存系统放到磁盘中了,如果内存也不能命中就要查磁盘

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

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

相关文章

甲方安全和乙方安全的区别

信息安全工作,总会被人分成甲方和乙方,甲乙方原本只是商务层面需方和供方的代称,在安全领域,成了做公司内部安全和为客户提供安全的区别。 通常意义上,什么是甲方安全人员呢?就是在非安全业务的公司从事信…

ROS2 通信三大件之动作 -- Action

通信最后一个,也是不太容易理解的方式action,复杂且重要 1、创建action数据结构 创建工作空间和模块就不多说了 在模块 src/action_moudle/action/Counter.action 下创建文件 Counter.action int32 target # Goal: 目标 --- int32 current_value…

[Python学习日记-45] Python 中模块的介绍与导入

[Python学习日记-45] Python 中模块的介绍与导入 简介 模块的概念与好处 模块的分类 模块导入和调用 自定义模块 模块的查找路径 简介 在前面的学习当中偶尔我们会看到 import ... 一个什么东西的,或者 from ... import ...,那时候并没有进行介绍&…

react+ts+vite 别名一直爆红问题

已经配置如下代码安装了types/node import path from "path"; // https://vitejs.dev/config/ export default defineConfig({plugins: [react()],server: {proxy: {"/api": {target: "http://localhost:3000",changeOrigin: true,rewrite: (pa…

如何选择安全的谷歌浏览器插件

在数字时代,浏览器插件为我们提供了极大的便利,增强了我们的浏览体验。然而,随着便利性的增加,安全性问题也日益凸显。选择安全的谷歌浏览器插件是保障个人信息安全的重要步骤。以下是详细的教程,帮助你选择和使用安全…

81 NAT-静态NAT

一 NAT 出口方向实验 1 配置接口的IP地址 2 配置nat 静态映射 3 测试 无法ping 通 202.38.1.100 4 接口上开启静态Nat映射规则 [FW-Router-BJ-GigabitEthernet0/1]nat static enable 6 5 查看配置 [FW-Router-BJ]display nat static 6 测试 7 查看NAT 会话状态 8 静态…

Qt自定义一个圆角对话框

如何得到一个圆角对话框? 步骤: 1、继承自QDiaglog 2、去掉系统自带的边框 3、设置背景透明,不设置4个角会有多余的部分出现颜色 4、对话框内部添加1个QWidget,给这个widget设置圆角,并添加到布局中让他充满对话框 5、后续对…

Redis协议详解及其异步应用

目录 一、Redis Pipeline(管道)概述优点使用场景工作原理Pipeline 的基本操作步骤C 示例(使用 [hiredis](https://github.com/redis/hiredis) 库) 二、Redis 事务概述事务的前提事务特征(ACID 分析)WATCH 命…

【HarmonyOS】HMRouter使用详解(二)路由跳转

路由跳转 HMRouter中使用HMRouterMgr的静态方法push()和replace()来实现路由跳转。使用pop()方法来实现页面返回 push :目标页面不会替换当前页,而是插入页面栈。可以使用pop实现页面的返回操作。replace:目标页面会替换当前页,并…

西门子828d的plc一些信息记录

1、虽然是200的plc但是引入了DB的形式替代原来的V存储区。 2、用户自定义DB块范围,DB9000-DB9063,共64个DB块。 可用地址范围如上图 机床MCP483面板地址表,其它类型的面板地址自己在828d简明调试手册里查看。 如何上载828d的plc程序: 1.通…

web-105linux权限提升

rsync未授权本地覆盖 Rsync 是 linux 下一款数据备份工具,默认开启 873 端口 https://vulhub.org/#/environments/rsync/common/ 借助 Linux 默认计划任务调用/etc/cron.hourly,利用 rsync 连接覆盖 前提条件就是需要知道rsync的密码或者存在未授权 -提…

【成品设计】基于Arduino平台的物联网智能灯

《基于Arduino平台的物联网智能灯》 整体功能: 这个任务中要求实现一个物联网智能灯。实际测试环境中要求设备能够自己创建一个热点,连接这个热点后能自动弹出控制界面(强制门户)。 功能点 基础功能 (60分) 要求作品至少有2个灯…

发布-订阅模式(Publisher-Subscriber)

实际上,发布-订阅模式只是观察者模式的一个别称。 但是经过时间的沉淀,似乎他已经强大了起来,已经独立于观察者模式,成为另外一种不同的设计模式。在现在的发布订阅模式中,称为发布者的消息发送者不会将消息直接发送给…

Linux下基本指令

Linux下基本指令 登录系统输入ssh root,在后面输入ip公用地址,按下enter键,会弹出一个密码框,输入密码即可登录成功。 Xshell下Altenter全屏,再重复操作是取消全屏。 clear清理屏幕。 01. ls 指令(用来…

[红队apt]文件捆绑攻击流程

免责声明:本文用于了解攻击者攻击手法,切勿用于不法用途 前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文整理黑客通过文件捆绑进行攻击的流程思路 文件捆绑原理 废话只多说这一句。 1.exe和2.exe被你捆绑为3.exe。 那么你点击了3.exe就等于点…

信息安全工程师(45)入侵检测系统组成与分类

前言 入侵检测系统(IDS)是一种网络安全设备或软件,能够监控和分析网络或系统活动,以检测和响应潜在的入侵行为。 一、入侵检测系统的组成 根据互联网工程任务组(IETF)的定义,一个典型的入侵检测…

文科类考研答题规范与卷面整洁度提升:高效备考的秘诀

随着考研竞争的日益激烈,考生们为了在众多竞争者中脱颖而出,纷纷寻求提升自己的备考策略,答题规范和卷面整洁度在文科类考研中显得尤为重要,本文将从答题规范和卷面整洁度两个方面,为广大文科类考研学子提供一些建议&a…

LeetCode刷题日记之回溯算法(一)

目录 前言组合组合总和III电话号码的字母组合总结 前言 今天开始学习回溯算法啦,虽然直接递归学习的时候有涉及到回溯但是没有系统性的学习,希望博主记录的内容能够对大家有所帮助 ,一起加油吧朋友们!💪💪…

飞腾X100适配Ubuntu说明

【写在前面】 飞腾开发者平台是基于飞腾自身强大的技术基础和开放能力,聚合行业内优秀资源而打造的。该平台覆盖了操作系统、算法、数据库、安全、平台工具、虚拟化、存储、网络、固件等多个前沿技术领域,包含了应用使能套件、软件仓库、软件支持、软件适…

实践体验密集小目标检测,以小麦麦穗颗粒为基准,基于嵌入式端超轻量级模型LeYOLO全系列【n/s/m/l】参数模型开发构建智能精准麦穗颗粒检测计数系统

对于常规的目标检测任务来说,诸如:COCO、VOC这类基础的数据场景,涌现出来了一些列性能初衷的检测模型,YOLO系列就是其中的佼佼者,不断地刷榜取得了越来越好的效果,不过这些评测指标是基于COCO、VOC这类公开…