聊聊高并发(五)理解缓存一致性协议以及对并发编程的影响

Java作为一个跨平台的语言,它的实现要面对不同的底层硬件系统,设计一个中间层模型来屏蔽底层的硬件差异,给上层的开发者一个一致的使用接口。Java内存模型就是这样一个中间层的模型,它为程序员屏蔽了底层的硬件实现细节,支持大部分的主流硬件平台。要理解Java内存模型以及一些处理高并发的技术手段,理解一些基本的硬件知识是必须的。这篇会说一下跟并发编程相关的一些硬件知识。

一个基本的CPU执行计算的过程如下:

1. 程序以及数据被加载到主内存

2. 指令和数据被加载到CPU的高速缓存

3. CPU执行指令,把结果写到高速缓存

4. 高速缓存中的数据写回主内存

这个过程中,我们可以看到有两个问题

1. 现代的计算芯片都会集成一个L1高速缓存,我们可以理解为每个芯片都有一个私有的存储空间。那么当CPU的不同计算芯片要访问同一个内存地址时,该内存地址的值会在CPU的不同计算芯片之间有多个拷贝,如何同步这些拷贝

2. CPU读写是直接和高速缓存打交道,而不是和主内存直接打交道。因为通常一次主存访问在几十到几百个时钟周期,而一次L1高速缓存的读写只需要1-2个时钟周期,而一次L2高速缓存的读写只需要数十个时钟周期。那么CPU写到高速缓存的值何时写回到主内?如果是多个计算芯片在处理同一个内存地址,那么如何处理这个时间差是个问题

对于第一个问题,不同的硬件结构处理的方式不一样。我们来理解一下互连线的概念。

互连线是处理器于主存以及处理器与处理器之间进行通信的媒介,有两种基本的互联结构:SMP(symmetric multiprocessing 对称多处理)和NUMA(nonuniform memory access 非一致内存访问)

SMP系统结构非常普通,因为它们最容易构建,很多小型服务器采用这种结构。处理器和存储器之间采用总线互联,处理器和存储器都有负责发送和监听总线广播的信息的总线控制单元。但是同一时刻只能有一个处理器(或存储控制器)在总线上广播,所有的处理器都可以监听

很容易看出,对总线的使用是SMP结构的瓶颈。

NUMP系统结构中,一系列节点通过点对点网络互联,像一个小型互联网,每个节点包含一个或多个处理器和一个本地存储器。一个节点的本地存储对于其他节点是可见的,所有节点的本地存储一起形成了一个可以被所有处理器共享的全局存储器。可以看出,NUMP的本地存储是共享的,而不是私有的,这点和SMP是不同的。NUMP的问题是网络比总线复制,需要更加复杂的协议,处理器访问自己节点的存储器速度快于访问其他节点的存储器。NUMP的扩展性很好,所以目前很多大中型的服务器在采用NUMP结构。

对于上层程序员来说,最需要理解的是互连线是一种重要的资源,使用的好坏会直接影响程序的执行性能。

大概理解了不同的互连结构之后,我们来看看缓存一致性协议。它主要就是处理多个处理器处理同一个主存地址的问题。

MESI是一种主流的缓存一致性协议,已经用在Pentium和PowerPC处理器中。它定义了缓存块的几种状态

  • modified(修改):缓存块已经被修改,必须被写回主存,其他处理器不能再缓存这个块
  • exclusive(互斥):缓存块还没有被修改,且其他处理器不能装入这个缓存块
  • share(共享):缓存块未被修改,且其他处理器可以装入这个缓存块
  • invalid(无效):缓存块中的数据无效

上图展示了MESI高速缓存一致性协议的状态转换实例。

1. 在a中,处理器A从地址a读取数据,将数据存入它的缓存并置为exclusive

2. 在b中,当处理器B试图从相同地址a读取数据时,A检测到地址冲突,以相关数据做出响应。此时a同时被A和B以shared状态装入缓存

3. 在c中,当B要对共享地址a进行写操作,则将状态改为modified,并广播提醒A,让它将它的缓存块状态设置为Invalid

4. 在d中,当A试图从a读取数据,会广播它的请求,B则把它修改的数据发送到A和主存,并设置两个副本的状态为shared来做出响应

更多缓存一致性协议的细节参考这篇 http://blog.csdn.net/realxie/article/details/7317630

缓存一致性协议存在的一个最大的问题是可能引起缓存一致性流量风暴,之前我们看到总线在同一时刻只能被一个处理器使用,当有大量缓存被修改,或者同一个缓存块一直被修改时,会产生大量的缓存一致性流量,从而占用总线,影响了其他正常的读写请求。

一个最常见的例子就是如果多个线程对同一个变量一直使用CAS操作,那么会有大量修改操作,从而产生大量的缓存一致性流量,因为每一次CAS操作都会发出广播通知其他处理器,从而影响程序的性能。

后面我们会讲如何优化这种使用方式。

对于第二个问题,如何处理修改数据从高速缓存到主内存的时间差,通常使用内存屏障来处理,后面会有专门的主题。

转载请注明来源:http://blog.csdn.net/iter_zc

时间: 2024-09-29 06:20:22

聊聊高并发(五)理解缓存一致性协议以及对并发编程的影响的相关文章

多核程序设计——缓存一致性协议MESI

MESI协议 在MP系统中,每个CPU都有自己独立的cache,缓存之间的一致性很很容易受到破坏的,所以缓存一致性协议就应运而生了.MESI是一种使用非常广泛的缓存一致性协议. MESI存在"modified","exclusive","shared"和"invalid"四种状态,协议可以在一个指定的缓存中应用这四种状态.因此,协议在每一个缓存行中维护一个两位的状态"tag",这个"tag&quo

一篇文章让你明白CPU缓存一致性协议MESI

CPU高速缓存(Cache Memory) CPU为何要有高速缓存 CPU在摩尔定律的指导下以每18个月翻一番的速度在发展,然而内存和硬盘的发展速度远远不及CPU.这就造成了高性能能的内存和硬盘价格及其昂贵.然而CPU的高度运算需要高速的数据.广州SEO为了解决这个问题,CPU厂商在CPU中内置了少量的高速缓存以解决I\O速度和CPU运算速度之间的不匹配问题. 在CPU访问存储设备时,无论是存取数据抑或存取指令,都趋于聚集在一片连续的区域中,这就被称为局部性原理. **时间局部性(Tempora

多线程之:MESI-CPU缓存一致性协议

MESI(Modified Exclusive Shared Or Invalid)(也称为伊利诺斯协议,是因为该协议由伊利诺斯州立大学提出)是一种广泛使用的支持写回策略的缓存一致性协议,该协议被应用在Intel奔腾系列的CPU中,详见“support the more efficient write-back cache in addition to the write-through cache previously used by the Intel 486 processor” MESI

缓存一致性协议MESI

1. 缓存一致性协议的由来: 计算机的存储设备速度与cpu的运算速度之间是数量级的差距,现代计算机不得不加入一层读写速度尽可能接近cpu运算速度的高速缓存来作为内存和cpu之间的缓冲:将运算需要使用到的数据复制到缓存中,让运算能快速进行,当运算结束后再从缓存同步回内存之中,这样cpu就无须等待缓慢的内存读写了. 基于高速缓存的存储交互很好地解决了cpu与内存的速度矛盾,但是也引入了新的问题:缓存一致性.在多cpu系统中,每个cpu都有自己的高速缓存,而它们又共享同一主内存,当多个cpu的运算任务

多线程之缓存一致性协议

前言: CPU在摩尔定律的指导下以每18个月翻一番的速度在发展,然而内存和硬盘的发展速度远远不及CPU.这就造成了高性能能的内存和硬盘价格及其昂贵.然而CPU的高度运算需要 高速的数据.为了解决这个问题,CPU厂商在CPU中内置了少量的高速缓存以解决I\O速度和CPU运算速度之间的不匹配问题. 首先在电脑中,CPU读取RAM中的数据数据的流程是,通过I/O总线(BUS),将数据从RAM中获取需要操作的数据进CPU需要如下几个步骤 CPU中的三级缓存从RAM中获取该数据. CPU中的二级缓存从三级

缓存一致性协议

刚看到一篇很好的介绍缓存一致性的文章,晚一点把其中的英文部分翻译过来 https://zhuanlan.zhihu.com/p/25876351 https://en.wikipedia.org/wiki/MESI_protocol

高并发下的缓存一致性问题

数据读取的时候: 先查缓存,缓存查不到查数据库,然后把查到的结果放到缓存中.这些都基本上没有争议. 但是数据更新的时候: 到底是先更新数据库,还是再更新(or删除)缓存 or 先更新(or删除)缓存,再更新数据库. 一直存在很大的争议.几种实现方式都会出现数据一致性问题. 我就说说目前我们系统是怎么做的: 0.先确认缓存命中率.不要动不动就上缓存,有些缓存命中率根本毫无意义,比如涉及到和账户相关的资产.订单等信息,就算放入缓存中,只有用户自己会去查自己的信息,命中率极低. 一般是把与账户无关,且

聊聊高并发(六)实现几种自旋锁(一)

在聊聊高并发(五)理解缓存一致性协议以及对并发编程的影响 我们了解了处理器缓存一致性协议的原理,并且提到了它对并发编程的影响,"多个线程对同一个变量一直使用CAS操作,那么会有大量修改操作,从而产生大量的缓存一致性流量,因为每一次CAS操作都会发出广播通知其他处理器,从而影响程序的性能." 这一篇我们通过两种实现自旋锁的方式来看一下不同的编程方式带来的程序性能的变化. 先理解一下什么是自旋,所谓自旋就是线程在不满足某种条件的情况下,一直循环做某个动作.所以对于自旋锁来锁,当线程在没有获

zt:缓存一致性(Cache Coherency)入门 cach coherency

http://www.infoq.com/cn/articles/cache-coherency-primer http://www.cnblogs.com/xybaby/p/6641928.html 本文是RAD Game Tools程序员Fabian “ryg” Giesen在其博客上发表的<Cache coherency primer>一文的翻译,经作者许可分享至InfoQ中文站.该系列共有两篇,本文系第一篇. 我计划写一些关于多核场景下数据组织的文章.写了第一篇,但我很快意识到有大量的