zoukankan      html  css  js  c++  java
  • Disruptor的伪共享解决方案

    1.术语

    术语

    英文单词

    描述

    内存屏障

    Memory Barriers

    是一组处理器指令,用于实现对内存操作的顺序限制。

     In the Java Memory Model a volatile field has a store barrier inserted after a write to it and a load barrier inserted before a read of it.

    缓存行

    Cache line

    缓存中可以分配的最小存储单位。处理器填写缓存线时会加载整个缓存线,需要使用多个主内存读周期。

    原子操作

    Atomic operations

    不可中断的一个或一系列操作。

    缓存行填充

    cache line fill

    当处理器识别到从内存中读取操作数是可缓存的,处理器读取整个缓存行到适当的缓存(L1,L2,L3的或所有)

    缓存命中

    cache hit

    如果进行高速缓存行填充操作的内存位置仍然是下次处理器访问的地址时,处理器从缓存中读取操作数,而不是从内存。

    写命中

    write hit

    当处理器将操作数写回到一个内存缓存的区域时,它首先会检查这个缓存的内存地址是否在缓存行中,如果不存在一个有效的缓存行,则处理器将这个操作数写回到缓存,而不是写回到内存,这个操作被称为写命中。

    写缺失

    write misses the cache

    一个有效的缓存行被写入到不存在的内存区域。

    一、 什么是伪共享

         在多处理器下,为了保证各个处理器的缓存是一致的,就会实现缓存一致性协议,每个处理器通过嗅探在总线上传播的数据来检查自己缓存的

    值是不是过期了,当处理器发现自己缓存行对应的内存地址被修改,就会将当前处理器的缓存行设置成无效状态,当处理器要对这个数据进行修改

    操作的时候,会强制重新从系统内存里把数据读到处理器缓存里。

      缓存行的大小是64字节。这意味着,小于64字节的变量,是有可能存在于同一条缓存行的。例如变量X大小32字节,变量Y大小32字节,

    那么他们有可能会存在于一缓存行上。

          当core 1上的线程想更新X,而core 2上的线程想更新Y,而X变量和Y变量在同一个缓存行中时;每个线程都要去竞争缓存行的所有权来更新变量。

    如果core 1获得所缓存行的所有权,那么缓存子系统将会使core 2中对应的缓存行失效,反之亦然。使x和y所在的缓存行来来回回的经过L3缓存,大大影响了

    性能。这种情况,就像多个线程同时获取锁的所有权一样。如果互相竞争的core位于不同的插槽,就要额外横跨插槽连接,问题可能更加严重。

    伪共享,就是多个线程同时修改共享在同一个缓存行里的独立变量,无意中影响了性能

    二、缓存行填充

    为什么追加64字节能够提高并发编程的效率呢

      因为对于英特尔酷睿i7,酷睿, Atom和NetBurst, Core Solo和Pentium M处理器的L1,L2或L3缓存的高速缓存行是64个字节宽,

    不支持部分填充缓存行,这意味着如果队列的头节点和尾节点都不足64字节的话,可以发生伪共享,而队列的入队和出队操作是需要不停修

    改头接点和尾节点,所以在多处理器的情况下将会严重影响到队列的入队和出队效率。

        /** head of the queue */
        private transient final PaddedAtomicReference < QNode > head;
     
        /** tail of the queue */
        private transient final PaddedAtomicReference < QNode > tail;
     
        static final class PaddedAtomicReference < T > extends AtomicReference < T > {
            // enough padding for 64bytes with 4byte refs 
    Object p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pa, pb, pc, pd, pe; PaddedAtomicReference(T r) { super(r); } } public class AtomicReference < V > implements java.io.Serializable { private volatile V value; }


    一个对象的引用占4个字节,它追加了15个变量共占60个字节,再加上父类的Value变量,一共64个字节。

    三、理解Disruptor的RingBuffer

    四、Log4j 2 使用Disruptor提高性能

    五、参考

    1.Disruptor

    2.海阔凭鱼跃从缓存行出发理解volatile变量、伪共享False sharing、disruptor

    3.美团:高性能队列——Disruptor

  • 相关阅读:
    微软企业库4.1学习笔记(十一)企业库的核心类 Virus
    微软企业库4.1学习笔记(七)创建对象 续集1 Virus
    微软企业库4.1学习笔记(五)对象创建和依赖注入方法 Virus
    微软企业库4.1学习笔记(十六)缓存模块4 服务器场中的缓存使用 Virus
    Android知识汇总
    移动UI研究学习汇总
    iOS独立存储Demo(调试过可以运行)
    The Official Preppy Handbook 目录
    一个好的App架构应该包括什么?
    转身再不仅仅只是开发人员
  • 原文地址:https://www.cnblogs.com/yuyutianxia/p/6365959.html
Copyright © 2011-2022 走看看