硬件结构(二)

硬件结构(二)

存储器金字塔

各种存储器之间的关系,可以用我们在图书馆学习这个场景来理解。

CPU 可以比喻成我们的大脑,我们当前正在思考和处理的知识的过程,就好比 CPU 中的寄存器处理数据的过程,速度极快,但是容量很小。而 CPU 中的 L1-L3 Cache 好比我们大脑中的短期记忆和长期记忆,需要小小花费点时间来调取数据并处理。

我们面前的桌子就相当于内存,能放下更多的书(数据),但是找起来和看起来就要花费些时间,相比 CPU Cache 慢不少。而图书馆的书架相当于硬盘,能放下比内存更多的数据但找起来就更费时间了,可以说是最慢的存储器设备了。

从 寄存器、CPU Cache,到内存、硬盘,这样一层层下来的存储器,访问速度越来越慢,存储容量越来越大,价格也越来越便宜,而且每个存储器只和相邻的一层存储器设备打交道于是这样就形成了存储器的层次结构。

那机械硬盘、固态硬盘、内存这三个存储器,到底和 CPU L1Cache 相比速度差多少倍呢?

CPU L1 Cache 随机访问延时是1 纳秒,内存则是 100 纳秒,所以CPU L1 Cache 比内存快100 倍左右。

SSD 随机访问延时是 150 微妙,所以 CPU L1 Cache 比 SSD 快 150000 倍左右

最慢的机械硬盘随机访问延时已经高达 10 毫秒,我们来看看机械硬盘到底有多 龟速

  • SSD 比机械硬盘快 70 倍左右;
  • 内存比机械硬盘快100000倍左右;
  • CPU L1 Cache 比机械硬盘快 10000000 倍左右

我们把上述的时间比例差异放大后,就能非常直观感受到它们的性能差异了。如果 CPU 访问L1 Cache 的缓存时间是1 秒,那访问内存则需要大约 2 分钟,随机访问 SSD 里的数据则需要 1.7 天,访问机械硬盘那更久,长达近 4 个月。

可以发现,不同的存储器之间性能差距很大,构造存储器分级很有意义,分级的目的是要构造缓存体系。

如何写出让CPU跑的更快的代码

由于随着计算机技术的发展,CPU 与 内存的访问速度相差越来越多,如今差距已经高达好几百倍了,所以 CPU 内部嵌入了 CPU Cache 组件,作为内存与 CPU 之间的缓存层,CPUCache 由于离 CPU 核心很近,所以访问速度也是非常快的,但由于所需材料成本比较高,它不像内存动辄几个 GB 大小,而是仅有几十 KB 到 MB 大小。

当 CPU 访问数据的时候,先是访问 CPU Cache,如果缓存命中的话,则直接返回数据,就不用每次都从内存读取速度了。因此,缓存命中率越高,代码的性能越好。

但需要注意的是,当 CPU 访问数据时,如果 CPU Cache 没有缓存该数据,则会从内存读取数据,但是并不是只读一个数据,而是一次性读取一块一块的数据存放到 CPU Cache 中,之后才会被 CPU 读取。

内存地址映射到 CPU Cache 地址里的策略有很多种,其中比较简单是直接映射 Cache,它巧妙的把内存地址拆分成索引+ 组标记 + 偏移量,的方式,使得我们可以将很大的内存地址,映射到很小的 CPU Cache 地址里。

要想写出让 CPU 跑得更快的代码,就需要写出缓存命中率高的代码,CPU L1 Cache 分为数据缓存和指令缓存,因而需要分别提高它们的缓存命中率:

  • 对于数据缓存,我们在遍历数据的时候,应该按照内存布局的顺序操作,这是因为 CPUCache 是根据 CPU Cache Line 批量操作数据的,所以顺序地操作连续内存数据时,性能能得到有效的提升;
  • 对于指令缓存,有规律的条件分支语句能够让 CPU 的分支预测器发挥作用,进一步提高执行的效率;

另外,对于多核 CPU 系统,线程可能在不同 CPU 核心来回切换,这样各个核心的缓存命中率就会受到影响,于是要想提高进程的缓存命中率,可以考虑把线程绑定 CPU 到某一个CPU 核心。

CPU 缓存一致性

CPU 在读写数据的时候,都是在 CPU Cache 读写数据的,原因是 Cache 离 CPU 很近,读写性能相比内存高出很多。对于 Cache 里没有缓存 CPU 所需要读取的数据的这种情况,CPU 则会从内存读取数据,并将数据缓存到 Cache 里面,最后 CPU 再从 Cache 读取数据。

而对于数据的写入,CPU 都会先写入到 Cache 里面,然后再在找个合适的时机写入到内存那就有 写直达写回这两种策略来保证 Cache 与内存的数据一致性:

  • 写直达,只要有数据写入,都会直接把数据写入到内存里面,这种方式简单直观,但是性能就会受限于内存的访问速度;
  • 写回,对于已经缓存在 Cache 的数据的写入,只需要更新其数据就可以,不用写入到内存,只有在需要把缓存里面的脏数据交换出去的时候,才把数据同步到内存里,这种方式在缓存命中率高的情况,性能会更好;

当今CPU 都是多核的,每个核心都有各自独立的 L1/L2 Cache,只有 L3 Cache 是多个核心之间共享的。所以,我们要确保多核缓存是一致性的,否则会出现错误的结果。

要想实现缓存一致性,关键是要满足 2 点:

  • 第一点是写传播,也就是当某个 CPU 核心发生写入操作时,需要把该事件广播通知给其他核心;
  • 第二点是事物的串行化,这个很重要,只有保证了这个,才能保障我们的数据是真正一致的,我们的程序在各个不同的核心上运行的结果也是一致的;

基于总线嗅探机制的 MESI(Modified(已修改),Exclusive(独享),Shared(共享),Invalid(已失效)) 协议,就满足上面了这两点,因此它是保障缓存一致性的协议.

MESI 协议,是已修改、独占、共享、已实现这四个状态的英文缩写的组合。整个 MSI 状态的变更,则是根据来自本地 CPU 核心的请求,或者来自其他 CPU 核心通过总线传输过来的请求,从而构成一个流动的状态机。另外,对于在已修改或者独占状态的 CacheLine,修改更新其数据不需要发送广播给其他 CPU 核心。

CPU 是如何执行任务的

理解 CPU 是如何读写数据的前提,是要理解 CPU 的架构,CPU 内部的多个 Cache + 外部的内存和磁盘都就构成了金字塔的存储器结构,在这个金字塔中,越往下,存储器的容量就越大,但访问速度就会小。

CPU 读写数据的时候,并不是按一个一个字节为单位来进行读写,而是以 CPU Line 大小为单位,CPU Line 大小一般是 64 个字节,也就意味着 CPU 读写数据的时候,每一次都是以64 字节大小为一块进行操作。

因此,如果我们操作的数据是数组,那么访问数组元素的时候,按内存分布的地址顺序进行访问,这样能充分利用到 Cache,程序的性能得到提升。但如果操作的数据不是数组,而是普通的变量,并在多核 CPU 的情况下,我们还需要避免 Cache Line 伪共享的问题。

所谓的 Cache Line 伪共享问题就是,多个线程同时读写同一个 Cache Line 的不同变量时而导致 CPU Cache 失效的现象。那么对于多个线程共享的热点数据,即经常会修改的数据应该避免这些数据刚好在同一个 Cache Line 中,避免的方式一般有 Cache Line 大小字节对齐,以及字节填充等方法。

系统中需要运行的多线程数一般都会大于 CPU 核心,这样就会导致线程排队等待 CPU,这可能会产生一定的延时,如果我们的任务对延时容忍度很低,则可以通过一些人为手段干预Linux 的默认调度策略和优先级。

软中断

为了避免由于中断处理程序执行时间过长,而影响正常进程的调度,Linux 将中断处理程序分为上半部和下半部:

  • 上半部,对应硬中断,由硬件触发中断,用来快速处理中断;
  • 下半部,对应软中断,由内核触发中断,用来异步处理上半部未完成的工作;

Linux 中的软中断包括网络收发、定时、调度、RCU 锁等各种类型,可以通过查看/proc/softirqs 来观察软中断的累计中断次数情况,如果要实时查看中断次数的变化率,可以使用 watch -d cat /proc/softirgs 命令

每一个 CPU 都有各自的软中断内核线程,我们还可以用 ps 命令来查看内核线程,一般名字在中括号里面到,都认为是内核线程。

如果在 top 命令发现,CPU 在软中断上的使用率比较高,而且 CPU 使用率最高的进程也是软中断 ksoftirgd 的时候,这种一般可以认为系统的开销被软中断占据了。

这时我们就可以分析是哪种软中断类型导致的,一般来说都是因为网络接收软中断导致的,如果是的话,可以用 sar 命令查看是哪个网卡的有大量的网络包接收,再用 tcpdump 抓网络包,做进一步分析该网络包的源头是不是非法地址,如果是就需要考虑防火墙增加规则,如果不是,则考虑硬件升级等。

为什么 0.1 + 0.2 != 0.3

为什么负数要用补码表示?

负数之所以用补码的方式来表示,主要是为了统一和正数的加减法操作一样,毕竟数字的加减法是很常用的一个操作,就不要搞特殊化,尽量以统一的方式来运算。

十进制小数怎么转成二进制?

十进制整数转二进制使用的是 除2 取余法,十进制小数使用的是乘 2 取整法]。

计算机是怎么存小数的?

  • 计算机是以浮点数的形式存储小数的,大多数计算机都是 EEE 754 标准定义的浮点数格式包含三个部分:
  • 符号位:表示数字是正数还是负数,为0表示正数,为 1 表示负数;
  • 指数位:指定了小数点在数据中的位置,指数可以是负数,也可以是正数,指数位的长度越长则数值的表达范围就越大;
    尾数位:小数点右侧的数字,也就是小数部分,比如二进制 1.0011 x 2-2),尾数部分就是 0011,而且尾数的长度决定了这个数的精度,因此如果要表示精度更高的小数,则就要提高尾数位的长度;

用32 位来表示的浮点数,则称为单精度浮点数,也就是我们编程语言中的 float 变量,而用64 位来表示的浮点数,称为双精度浮点数,也就是 double 变量。

0.1 +0.2== 0.3 吗?

不是的,0.1 和0.2 这两个数字用二进制表达会是一个一直循环的二进制数,比如 0.1 的二进制表示为 0.0 0011 0011 0011… (0011 无限循环),对于计算机而言,0.1 无法精确表达,这是浮点数计算造成精度损失的根源。

因此,IEEE 754 标准定义的浮点数只能根据精度舍入,然后用近似值来表示该二进制那么意味着计算机存放的小数可能不是一个真实值。

0.1+0.2 并不等于完整的 0.3,这主要是因为这两个小数无法用完整的二进制来表示,只能根据精度舍入,所以计算机里只能采用近似数的方式来保存,那两个近似数相加,得到的必然也是一个近似数。

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

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

相关文章

【Python百宝箱】声音的数字化探索:Python引领音频奇妙世界

Python音频魔力:数字化时代的声音创意探索 前言 在数字化时代,声音技术的迅速发展不仅革新了音乐产业,也在语音识别、虚拟现实、智能系统等领域引发了革命性变革。Python作为强大的编程语言,引领着音频处理与分析的新潮流。本文…

JVM中的双亲委派模型

双亲委派模型(Parent-Delegation Model)是Java类加载器(ClassLoader)机制的一种实现方式。它是Java中实现类加载的一种层次结构模型。 双亲委派模型的工作过程是:在Java中,每个类加载器实例都有一个父类加载…

多头注意力机制基本概念

文章目录 基本概念模型小结 基本概念 我们可以用独立学习得到的h组不同的 线性投影来变换查询、键和值。 然后,这h组变换后的查询、键和值将并行地送到注意力汇聚中。 最后,将这h个注意力汇聚的输出拼接在一起, 并且通过另一个可以学习的线性…

Vue+SpringBoot项目前端如何获取本地磁盘路径的照片

一、问题 今日项目中遇到的问题: 在页面想要展示本地磁盘路径的照片,但是一直无法显示出来 原因:可能是vue无法直接读取本地磁盘的照片(本人盲猜) 1.解决思路 1.后端进行静态资源映射 2.前端调用 2.实现步骤一 在后端的…

PostgreSQL 修改表字段名称

用SQL语句进行修改,一条语句就可以搞定: 当你字段名有多余空格的时候,使用这种方法则可以进行修改为新的字段名 ALTER TABLE table_name RENAME COLUMN "旧字段名" TO "新字段名";

你要了解的 OpenAI 那些事:创立简史,技术背景等

原文: https://openaigptguide.com/what-is-openai/ OpenAI 是一家人工智能研究公司,成立于2015年,总部位于美国旧金山。目前,OpenAI由创始人Sam Altman、首席技术官Ilya Sutskever、首席执行官Ilya Sutskever(同时担…

Keil报错_Error:CreateProcess failed,Command:‘xxx\fromelf.exe‘

1、报错信息 2、分析及解决 错误原因:fromelf.exe路径错误,无法执行命令。 发生情景:编译从另一个电脑拷贝的代码时。 解决方法: 1、当你不需要生成bin文件时,可以选择不执行这个命令。(去掉√&#xf…

每日一练2023.11.27———连续因子【PTA】

题目要求: 一个正整数 N 的因子中可能存在若干连续的数字。例如 630 可以分解为 3567,其中 5、6、7 就是 3 个连续的数字。给定任一正整数 N,要求编写程序求出最长连续因子的个数,并输出最小的连续因子序列。 输入格式&#xff…

在工程中输出尽量用log而不用直接打印

在工程中输出尽量用log而不用直接打印 工程中,建议尽量使用日志(log)系统而不是直接使用 printf 函数进行输出。这是因为日志系统可以提供更强大和灵活的功能,同时也具有以下优点: 可配置性: 日志系统通常具有配置选项…

百度智能云正式上线Python SDK版本并全面开源

文章目录 前言一、SDK的优势二、千帆SDK:快速落地LLM应用三、如何快速上手千帆SDK3.1、SDK快速启动3.2. SDK进阶指引 3.3. 通过Langchain接入千帆SDK4、开源社区 前言 百度智能云千帆大模型平台再次升级!在原有API基础上,百度智能云正式上线…

Jenkins Pipeline应用实践

Jenkins Pipeline是一种可编程的、可扩展的持续交付管道,允许您使用脚本来定义整个软件交付过程。 以下是使用Jenkins Pipeline创建和配置流水线的基本步骤。 Part 01. 创建一个Pipeline Job 在Jenkins中创建一个新的"Pipeline"类型的Job。 以下是在Je…

跨境电商与物联网:智能设备的未来

随着科技的不断发展,跨境电商和物联网的结合呈现出前所未有的新格局。在这个数字化的时代,智能设备正成为跨境电商的新宠,为商业、物流和消费者带来了全新的体验。本文将深入探讨跨境电商与物联网的结合,探讨智能设备在未来的发展…

nrm : 镜像源工具npm镜像切换

nrm命令 安装nrm&#xff1a;npm i -g nrm 查看镜像源&#xff1a;nrm ls&#xff0c;带*号的为当前使用的源 添加新镜像&#xff1a;nrm add [镜像源名称] <源的URL路径> 切换镜像源&#xff1a;nrm use [镜像源名称] 删除一个镜像源&#xff1a;nrm del [镜像源名称] …

为什么制定交易策略要根据资金量,澳福一个例子说清楚

为什么制定交易策略要根据资金量。其实很简单&#xff0c;澳福一个例子说清楚。 假如投资者现在有一大笔资金&#xff0c;就可以用这笔资金的1个百分点的利息来支付自己的日常开支&#xff0c;一百万的1%利息就足够了&#xff0c;可以支付你想要的一切。澳福和各位投资者是不是…

【axios】拦截器:axios.interceptors.request.use|axios.interceptors.response.use

文章目录 概述设置拦截器Axios 拦截器的实现任务注册任务编排任务调度 来源 概述 axios有请求拦截器&#xff08;request&#xff09;、响应拦截器&#xff08;response&#xff09;、axios自定义回调处理&#xff08;这里就是我们常用的地方&#xff0c;会将成功和失败的回调…

成为一名优秀教师的关键要素

在教育领域&#xff0c;要想成为一名优秀的教师可是需要多方面的素质和技能的。以下是我总结出的几点关键要素&#xff0c;供大家参考。 热爱教育事业 首先对教育事业充满热爱和热情。只有对事业有强烈的兴趣和热爱&#xff0c;才能在漫长的工作中保持耐心、专注和投入。热爱教…

2023年【通信安全员ABC证】考试题及通信安全员ABC证证考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年【通信安全员ABC证】考试题及通信安全员ABC证证考试&#xff0c;包含通信安全员ABC证考试题答案和解析及通信安全员ABC证证考试练习。安全生产模拟考试一点通结合国家通信安全员ABC证考试最新大纲及通信安全员A…

基于springboot+maven的个人理财管理系统

基于springbootmaven的个人理财管理系统,演示地址:个人理财系统登录界面 用户名:admin,密码&#xff1a;123456 共分为用户信息管理(用户信息&#xff0c;银行卡&#xff0c;个人征信)&#xff0c;理财产品管理(零钱理财&#xff0c;工资理财&#xff0c;期限理财&#xff0c…

FLASK博客系列9——你想成为我的新用户吗?

距离上次发文好久好久了。 先说声抱歉&#xff0c;拖更的毛病我会改掉的。 上次我们教大家如何用后台去管理用户和新增文章&#xff0c;但始终都是单机操作&#xff0c;怎么让你的朋友也来加入你的小站呢&#xff1f;今天我们来为我们的网站增添一个新功能&#xff0c;实现用户…

文心一言 VS 讯飞星火 VS chatgpt (144)-- 算法导论12.1 4题

四、用go语言&#xff0c;对于一棵有 n 个结点的树&#xff0c;请设计在 O(n)时间内完成的先序遍历算法和后序遍历算法。 我个人喜欢 灵小智 。 文心一言&#xff1a; 在 Go 语言中&#xff0c;我们可以使用递归来实现树的前序遍历和后序遍历。以下是实现这两种方法的代码。…