本文将详细解释如何共享和缓存中断器。文章内容质量很高,我就分享给大家作为参考。希望大家看完这篇文章后对相关知识有一定的了解。
00-1010下图是计算的基本结构。L1、L2、L3分别代表一级缓存、二级缓存和三级缓存。越靠近CPU的缓存,速度越快,容量越小。因此,L1缓存虽小但速度快,而且离使用它的CPU内核很近。L2更大更慢,仍然只能由单个中央处理器内核使用。L3更大、更慢,由单个插槽上的所有CPU内核共享;最后是主存,由所有插槽中的所有CPU内核共享。
图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:队列中元素的数量
这三个变量很容易放到一个缓存行中,但是之间修改没有太多的关联。所以每次修改,都会使之前缓存的数据失效,从而不能完全达到共享的效果。
图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