Disruptor的共享与缓存是怎样的

技术Disruptor的共享与缓存是怎样的这篇文章将为大家详细讲解有关Disruptor的共享与缓存是怎样的,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。什么是共享下图是

本文将详细解释如何共享和缓存中断器。文章内容质量很高,我就分享给大家作为参考。希望大家看完这篇文章后对相关知识有一定的了解。

00-1010下图是计算的基本结构。L1、L2、L3分别代表一级缓存、二级缓存和三级缓存。越靠近CPU的缓存,速度越快,容量越小。因此,L1缓存虽小但速度快,而且离使用它的CPU内核很近。L2更大更慢,仍然只能由单个中央处理器内核使用。L3更大、更慢,由单个插槽上的所有CPU内核共享;最后是主存,由所有插槽中的所有CPU内核共享。

Disruptor的共享与缓存是怎样的

图3计算机CPU和缓存示意图。

当中央处理器执行操作时,它首先去L1查找所需的数据,然后去L2,然后去L3。如果这些缓存最终都不可用,所需的数据将进入主内存。你走得越远,计算的时间就越长。因此,如果您非常频繁地执行某项操作,您应该尝试确保数据在L1缓存中。

另外,线程之间共享一条数据时,一个线程需要将数据写回主存,而另一个线程需要访问主存中对应的数据。

以下是从CPU访问不同级别数据的时间概念:

从CPU到所需CPU周期所需的时间约为60-80nsQPI总线传输(套接字之间,未画出),约20nsL3缓存,约40-45周期,约15nsL2缓存,约10周期,约3nsL1缓存,约3-4周期,约1ns寄存器,1周期。可以看出,CPU读取主存中的数据会比L1慢近两个数量级。

什么是共享

缓存由许多缓存行组成。每个高速缓存行通常是64字节,它实际上是指主存储器中的一个地址块。一个Java长变量是8字节,所以一个缓存行可以存储8个长变量。

每次中央处理器从主存储器中提取数据时,它也会将相邻的数据存储到同一高速缓存行中。

当访问长数组时,如果数组中的一个值被加载到缓存中,它将自动加载其他七个值。所以你可以非常快速地遍历这个数组。事实上,您可以非常快速地遍历在连续内存块中分配的任何数据结构。

以下示例测试使用缓存线和不使用缓存线的要素之间的效果比较。

package com . meituan . Falssharing;

/**

*@authorgongming

* @描述

*@date16/6/4

*/

publicclassCacheLineEffect{

//考虑一般缓存行大小为64字节,长类型占用8字节。

static long[][]arr;

publicationstativitmain(String[]args){ 0

arr=new long[1024 * 1024][];

for(inti=0;i1024 * 1024I){ 0

arr[I]=new long[8];

(=NationalBureauofStandards)国家标准局

p;for (int j = 0; j < 8; j++) {
                arr[i][j] = 0L;
            }
        }
        long sum = 0L;
        long marked = System.currentTimeMillis();
        for (int i = 0; i < 1024 * 1024; i+=1) {
            for(int j =0; j< 8;j++){
                sum = arr[i][j];
            }
        }
        System.out.println("Loop times:" + (System.currentTimeMillis() - marked) + "ms");
 
        marked = System.currentTimeMillis();
        for (int i = 0; i < 8; i+=1) {
            for(int j =0; j< 1024 * 1024;j++){
                sum = arr[j][i];
            }
        }
        System.out.println("Loop times:" + (System.currentTimeMillis() - marked) + "ms");
    }
}

在2G Hz、2核、8G内存的运行环境中测试,速度差一倍。

结果: Loop times:30ms Loop times:65ms

什么是伪共享

ArrayBlockingQueue有三个成员变量: - takeIndex:需要被取走的元素下标 - putIndex:可被元素插入的位置的下标 - count:队列中元素的数量

这三个变量很容易放到一个缓存行中,但是之间修改没有太多的关联。所以每次修改,都会使之前缓存的数据失效,从而不能完全达到共享的效果。

Disruptor的共享与缓存是怎样的

图4 ArrayBlockingQueue伪共享示意图

如上图所示,当生产者线程put一个元素到ArrayBlockingQueue时,putIndex会修改,从而导致消费者线程的缓存中的缓存行无效,需要从主存中重新读取。

这种无法充分使用缓存行特性的现象,称为伪共享。

对于伪共享,一般的解决方案是,增大数组元素的间隔使得由不同线程存取的元素位于不同的缓存行上,以空间换时间。

package com.meituan.FalseSharing;
 
public class FalseSharing implements Runnable{
        public final static long ITERATIONS = 500L * 1000L * 100L;
        private int arrayIndex = 0;
 
        private static ValuePadding[] longs;
        public FalseSharing(final int arrayIndex) {
            this.arrayIndex = arrayIndex;
        }
 
        public static void main(final String[] args) throws Exception {
            for(int i=1;i<10;i++){
                System.gc();
                final long start = System.currentTimeMillis();
                runTest(i);
                System.out.println("Thread num "+i+" duration = " + (System.currentTimeMillis() - start));
            }
 
        }
 
        private static void runTest(int NUM_THREADS) throws InterruptedException {
            Thread[] threads = new Thread[NUM_THREADS];
            longs = new ValuePadding[NUM_THREADS];
            for (int i = 0; i < longs.length; i++) {
                longs[i] = new ValuePadding();
            }
            for (int i = 0; i < threads.length; i++) {
                threads[i] = new Thread(new FalseSharing(i));
            }
 
            for (Thread t : threads) {
                t.start();
            }
 
            for (Thread t : threads) {
                t.join();
            }
        }
 
        public void run() {
            long i = ITERATIONS + 1;
            while (0 != --i) {
                longs[arrayIndex].value = 0L;
            }
        }
 
        public final static class ValuePadding {
            protected long p1, p2, p3, p4, p5, p6, p7;
            protected volatile long value = 0L;
            protected long p9, p10, p11, p12, p13, p14;
            protected long p15;
        }
        public final static class ValueNoPadding {
            // protected long p1, p2, p3, p4, p5, p6, p7;
            protected volatile long value = 0L;
            // protected long p9, p10, p11, p12, p13, p14, p15;
        }
}

在2G Hz,2核,8G内存, jdk 1.7.0_45 的运行环境下,使用了共享机制比没有使用共享机制,速度快了4倍左右。

结果: Thread num 1 duration = 447 Thread num 2 duration = 463 Thread num 3 duration = 454 Thread num 4 duration = 464 Thread num 5 duration = 561 Thread num 6 duration = 606 Thread num 7 duration = 684 Thread num 8 duration = 870 Thread num 9 duration = 823

把代码中ValuePadding都替换为ValueNoPadding后的结果: Thread num 1 duration = 446 Thread num 2 duration = 2549 Thread num 3 duration = 2898 Thread num 4 duration = 3931 Thread num 5 duration = 4716 Thread num 6 duration = 5424 Thread num 7 duration = 4868 Thread num 8 duration = 4595 Thread num 9 duration = 4540

备注:在jdk1.8中,有专门的注解@Contended来避免伪共享,更优雅地解决问题。

关于Disruptor的共享与缓存是怎样的就分享到这里了,希望

内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/39236.html

(0)

相关推荐

  • 满足解决配置DG Broker时报错Error: ORA-16698问题

    技术满足解决配置DG Broker时报错Error: ORA-16698问题这篇文章主要介绍“满足解决配置DG Broker时报错Error: ORA-16698问题”,在日常操作中,相信很多人在满足解决配置DG Bro

    攻略 2021年11月10日
  • 引擎ECS框架中system的语法糖是怎么实现的

    技术引擎ECS框架中system的语法糖是怎么实现的引擎ECS框架中system的语法糖是怎么实现的,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。集(B

    攻略 2021年11月24日
  • MySQL FLTWL的堵塞和被堵塞分析

    技术MySQL FLTWL的堵塞和被堵塞分析这篇文章主要介绍“MySQL FLTWL的堵塞和被堵塞分析”,在日常操作中,相信很多人在MySQL FLTWL的堵塞和被堵塞分析问题上存在疑惑,小编查阅了各式资料,整理出

    攻略 2021年11月10日
  • 狗能吃猫粮么,狗常吃猫粮会怎样

    技术狗能吃猫粮么,狗常吃猫粮会怎样狗常吃猫粮是有害处的,长期饲喂猫粮,狗狗会因为无法消化高量的蛋白质而出现胃肠敏感,甚至出现呕吐、腹泻等症状狗能吃猫粮么。随特别是对肝肾功能本来就有问题的狗狗来说,过多的蛋白质更是禁忌。

    生活 2021年10月26日
  • 怎样从Oracle到GaussDB的数据迁移

    技术怎样从Oracle到GaussDB的数据迁移今天就跟大家聊聊有关怎样从Oracle到GaussDB的数据迁移,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。 一

    攻略 2021年11月30日
  • Shuffle原理及对应的Consolidation优化机制是怎样的

    技术Shuffle原理及对应的Consolidation优化机制是怎样的这篇文章给大家介绍Shuffle原理及对应的Consolidation优化机制是怎样的,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所

    攻略 2021年12月3日