iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >内存屏障由来及实现思路
  • 423
分享到

内存屏障由来及实现思路

2024-04-02 19:04:59 423人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

目录01 CPU缓存02 缓存的一致性03 内存屏障的由来04 内存屏障实现思路很多人知道内存屏障这个东西应该是在学习volatile时看到的,但是对内存屏障依然存在很多疑惑:为什么

很多人知道内存屏障这个东西应该是在学习volatile时看到的,但是对内存屏障依然存在很多疑惑:为什么要加内存屏障?内存屏障能解决什么问题?为什么能解决这些问题?

最近在研究volatile的过程中发现内存屏障这东西如果不搞明白,Java中的volatile就别想学透,所以花了较长时间来研究这块。看了很多资料,写了很多代码测试,这篇文章就来总结下我目前认知中的内存屏障。

01 CPU缓存

如果你不了解讲内存屏障为什么要讲CPU缓存,接着往后看。

学过《计算机组成原理》的同学应该都听过一个词:时钟周期。什么是时钟周期呢?通俗点来讲就是CPU完成一个基本动作需要的时间周期。对硬件有点认识的同学都知道看CPU好不好一定要看的一个参数:多少多少GHZ。这个GHZ跟时钟周期之间是存在一定的换算关系的,感兴趣的同学可以去自行研究。说明一下:不了解这层换算关系不影响你看后面的内容,只要你对时钟周期有一个基本认知就可以了。

在很早以前,CPU里面是没有缓存这块区域的,就是CPU直接读写内存。那后面为什么在CPU中增加了缓存呢?因为CPU的运行效率与读写内存的效率存在着巨大的鸿沟,在读写内存过程中带来的等待浪费了很大的CPU算力。现在最新的内存是DDR4规格,但是向内存中写入数据,据权威资料,需要107个CPU时钟周期,即CPU的运行效率是写内存的107倍。如果CPU只执行写操作需要一个时钟周期,那CPU等待这个写完成需要等待106个时钟周期,是不是很浪费CPU算力?那如何解决呢?就跟我们工作中发现Mysql出现读写瓶颈如何解决是一样的思维:加缓存。

拿我们今天主流的CPU架构来说,现在的CPU主要采用三层缓存:

  • L1、L2缓存成为本地核心内缓存,即一个核一个。如果你的机器是4核,那就是有4个L1+4个L2

  • L3缓存是所有核共享的。即不管你的CPU是几核,这个CPU中只有一个L3

  • L1缓存的大小是64K,即32K指令缓存+32K数据缓存。L2是256K,L3是2M。这不是绝对的,目前Intel CPU基本是这样的设计

这里还补充一个知识点:缓存行(Cache-line)。缓存行是CPU缓存存储数据的最小单位,大小为64B。这块如果展开来讲要讲很久很久,本篇文章就不展开讲了,有兴趣的同学可以自行研究。如果你没有学习过计算机硬件相关知识,可能看不懂。

根据哲学的矛盾相对论:任何问题的解决方案都是一个利与弊共存的矛盾体。加缓存的确有效提升了CPU的执行效率,但是CPU缓存间的数据一致性、CPU缓存与内存间的数据一致性就是不得不去思考与解决的问题了。而且还得保证解决这两层数据一致性的效率要高于不加缓存前浪费的CPU算力,不然这个方案就是一套伪方案:听起来高大上,不解决问题。

02 缓存的一致性

MESI协议就是为了保证CPU各核的缓存、内存间的数据一致性而生的,没有了解过的可以百度普及一下,这个比较简单。这里拓展两点:

一、CPU运算单元与L1缓存间为什么要增加buffer?CPU实现各个核的缓存与内存间的数据一致性的思路有点像Socket的三次握手:CPU0修改了某个数据,需要广播告诉其他CPU,这时候CPU0进入阻塞状态等待其他CPU修改其缓存中的状态,待其他CPU都修改完状态返回应答消息后才进入运行状态。虽然这个阻塞的时间很短,但是在CPU的世界里就很长了,为了保证这部分阻塞时间也能得到充分利用,于是加入了buffer。将预读信息存储进去,这样CPU解除阻塞后就可以直接从buffer拿出请求处理。

二、MESI协议的实现思路是:如果CPU0修改了某个数据,需要广播给其他CPU,缓存中没有这个数据的CPU丢弃这个广播消息,缓存中有这个数据的CPU监听到这个广播后会将相应的缓存行改为invalid状态,这样CPU在下次读取这个数据的时候发现缓存行失效,就去内存中读取。这里面童鞋们有没有发现一个问题:只要存在数据修改,CPU就需要去内存取数据,那为什么不实现CPU缓存能共享数据呢?这样CPU在下次读取的时候去CPU0的缓存行去读取就可以啦,而且性能更高。现在的CPU也的确实现了这个思路,对应的协议就是:AMD的MOESI、Intel的MESIF。感兴趣的童鞋自己去研究吧。

03 内存屏障的由来

对于CPU的写,目前主流策略有两种:

1、write back:即CPU向内存写数据时,先把真实数据放入store buffer中,待到某个合适的时间点,CPU才会将store buffer中的数据刷到内存中,而且这两个操作是异步的。这在多线程环境中,有些情况下是可以接受的,但是有些情况是不可接受的,为了让程序员有能力根据业务需要达到同步完成,就设计了内存屏障。关于内存屏障,后面会细讲。

2、write through:即CPU向内存写数据时,同步完成写store buffer与内存。

当前CPU大多数采用的是write back策略。可能有童鞋要问了:为什么呢?因为大多数情况下,CPU异步完成写内存产生的部分延迟是可以接受的,而且这个延迟极短。只有在多线程环境下需要严格保证内存可见等极少数特殊情况下才需要保证CPU的写在外界看来是同步完成的,需要借助CPU提供的内存屏障实现。如果直接采用策略2:write through,那每次写内存都需要等待数据刷入内存,极大影响了CPU的执行效率。

04 内存屏障实现思路

为什么要插入屏障?本质是业务层面不能接受写store buffer与刷回内存这两个异步操作产生的哪怕是极少的延迟,即对内存可见性的要求极高。

内存屏障到底是什么?内存屏障什么都不是,它只是一个抽象概念,就像OOP。如果这样说你不理解,那你把他理解成一堵墙,这堵墙正面与反面的指令无法被CPU乱序执行及这堵墙正面与反面的读写操作需有序执行。

CPU提供了三个汇编指令串行化运行读写指令达到实现保证读写有序性的目的:

SFENCE:在该指令前的写操作必须在该指令后的写操作前完成

LFENCE:在该指令前的读操作必须在该指令后的读操作前完成

MFENCE:在该指令前的读写操作必须在该指令后的读写操作前完成

何谓串行化?你可以理解成CPU把读、写、读写请求放入了一个队列,按照先进先出的顺序执行下去;何谓读操作完成,即CPU执行一次读操作,把值读到了寄存器中;何谓写操作完成,即CPU执行一次写操作,数据刷到内存中了。

到这里就把内存屏障讲清楚了,你悟了吗?

以上就是内存屏障由来及实现思路的详细内容,更多关于内存屏障的资料请关注编程网其它相关文章!

--结束END--

本文标题: 内存屏障由来及实现思路

本文链接: https://www.lsjlt.com/news/138074.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 内存屏障由来及实现思路
    目录01 CPU缓存02 缓存的一致性03 内存屏障的由来04 内存屏障实现思路很多人知道内存屏障这个东西应该是在学习volatile时看到的,但是对内存屏障依然存在很多疑惑:为什么...
    99+
    2024-04-02
  • 计算机中内存屏障由来及实现思路
    这篇文章给大家分享的是有关计算机中内存屏障由来及实现思路的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。01 CPU缓存如果你不了解讲内存屏障为什么要讲CPU缓存,接着往后看。学过《计算机组成原理》的同学应该都听过...
    99+
    2023-06-29
  • Flutter实现页面路由及404路由拦截
    为什么要使用路由 在之前我们的代码中,页面跳转使用的代码如下所示: Navigator.of(context).push( MaterialPageRoute(builde...
    99+
    2024-04-02
  • Flutter app页面路由以及路由拦截的实现
    目录为什么要使用路由 Flutter路由介绍 页面结构与逻辑 实现关键代码 页面路由跳转 为什么要使用路由 在之前我们的代码中,页面跳转使用的代码如下所示: Navigato...
    99+
    2024-04-02
  • C++高并发内存池的整体设计和实现思路
    目录一、整体设计1、需求分析2、总体设计思路3、申请内存流程图二、详细设计1、各个模块内部结构详细剖析2、设计细节三、测试一、整体设计 1、需求分析 池化技术是计算机中的一种设计模式...
    99+
    2024-04-02
  • vue-router路由懒加载及实现方式
    目录vue-router路由懒加载及实现方式。前言一、路由懒加载二、实现路由懒加载1.Vue异步组件(异步加载)2.推荐方式-ES6的import() 3.webpack提...
    99+
    2022-12-15
    vue-router路由懒加载 路由懒加载实现方式
  • react中路由跳转及传参的实现
    目录1.useNavigate2.useLocation3.示例1.useNavigate useNavigate 是 React Router v6 中新增的一个 hoo...
    99+
    2023-05-19
    react 路由跳转 react 路由传参
  • Flutter路由传递参数及解析实现
    上一篇Flutter页面路由及404路由拦截实现介绍了使用路由来实现页面的跳转,从而简化页面之间的耦合,并可以实现路由拦截。在实际开发中,我们经常会需要在页面跳转的时候携带路由参数...
    99+
    2024-04-02
  • vue路由模式有哪些及怎么实现
    本篇内容介绍了“vue路由模式有哪些及怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!vue路由模式有:1、hash模式,使用URL的...
    99+
    2023-07-04
  • react diff 算法实现思路及原理解析
    目录事例分析diff 特点diff 思路实现 diff 算法修改入口文件实现 React.Fragment我们需要修改 children 对比前面几节我们学习了解了 react 的渲...
    99+
    2024-04-02
  • vue中路由的两种模式以及实现原理
    Vue.js 是一种流行的前端框架,通过其优秀的路由管理模块实现了单页应用(Single-page Application,SPA)的开发。Vue 路由管理模块(Vue Router)具有两种模式:历史模式(History mode)和哈希...
    99+
    2023-05-23
  • 通过Java修改游戏存档的实现思路
    目录前言一、实现思路二、项目准备1. 创建maven工程2. 导入依赖三、核心代码1. 使用的对象2. 修改关卡信息3. 修改金币信息四、代码测试1. 读取数据文件2. 修改关卡位置...
    99+
    2024-04-02
  • 如何在Go语言中实现路由的请求缓存
    如何在Go语言中实现路由的请求缓存在Web开发中,路由是一个非常重要的概念,用于将客户端请求映射到相应的处理程序。在高并发的情况下,频繁地处理请求可能会导致服务器性能下降。为了减轻服务器的负载和提高响应速度,可以对路由的请求进行缓存。在Go...
    99+
    2023-12-17
    Go语言 路由 请求缓存
  • 使用 C++ 函数的内存分配和销毁来实现内存池
    c++++ 函数的内存分配和销毁可用于实现内存池,从而提高性能。内存池预先分配内存块并重复使用,避免了频繁的系统分配和释放操作。可定义内存分配函数 poolallocate 和内存销毁函...
    99+
    2024-04-22
    c++ 内存池
  • 手写mybatis完整sql插件问题及实现思路
    问题产生 我们在使用mybatis的过程中,如果开启了mysql的日志功能的话,会在控制台打印一些sql的信息,但是日志中的sql语句,是没有拼接参数的,也就是说,是不可以直接放到数...
    99+
    2024-04-02
  • element实现导航栏收起展开功能及思路
    目录element 导航栏收起展开实现思路PS:Vue结合element-ui实现导航菜单展开收缩小功能上篇文章介绍了vue使用ElementUI时导航栏默认展开功能的实现,今天介绍...
    99+
    2023-01-16
    element 导航栏收起展开 element 导航栏收起 element 导航栏 element-ui展开收缩
  • vue中keep-alive组件实现多级嵌套路由的缓存
    目录现状(问题):探索方案:实现方式现状(问题): keep-alive 组件对第三级及以上级的路由页面缓存失效 探索方案: 方案1、直接将路由扁平化配置,都放在一级或二级路由中方案...
    99+
    2024-04-02
  • Vue3嵌套路由中使用keep-alive缓存多层的实现
    目录前言Demo项目结构路由层级扁平化给所有的 router-view 都嵌套上 keep-alive前言 keep-alive是Vue中的缓存标签, 组件在标签中的内容会被缓存下来...
    99+
    2023-05-16
    Vue3 keep-alive缓存多层 Vue3 缓存多层
  • C语言实现冒泡排序的思路以及过程
    目录C语言实现<冒泡排序>整体思路代码实现C语言实现<冒泡排序> 你们好!我是飞人!此篇文章是我进入IT行业第一篇博客,若有不妥之处,欢迎指点。 此篇讲解冒泡...
    99+
    2024-04-02
  • Oracle SQL中实现indexOf和lastIndexOf功能的思路及代码
    在 Oracle SQL 中,没有直接提供类似于 indexOf 和 lastIndexOf 的内置函数。但可以通过使用其他字符串函...
    99+
    2023-08-16
    Oracle
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作