并发编程的基础知识(二)

1 什么是伪共享

为了解决计算机系统中主内存与CPU之间运行速度差的问题,会在CPU与主内存之间添加一级或者多级高速缓冲存储器(Cache)。这个Cache一般是被集成到CPU内部的,所以也称为CPU Cache。图1-1是两级Cache结构示意图。
两级Cache结构
在Cache内部是按行进行存储的,其中每一行称为一个Cache行。Cache行是Cache与主内存进行数据交换的单位,Cache行的大小一般为2的幂次方字节。Cache如下图所示。
Cache
当CPU访问某个变量时,首先会去看Cpu Cache内是否有该变量,如果有则直接从里面获取,否则就去主内存里面获取该变量,然后把该变量所在内存区域的一个Cache行大小的内存复制到Cache中。由于存放到Cache行的是内存块,而不是单个变量,所以可能会把多个变量存放到一个Cache行里面。当多个变量同时修改同一个缓存行里面的多个变量时,由于同时只能有一个线程操作缓存行,所以相比将每个变量放到一个缓存行,性能会有所下降,这就是伪共享。

图1-3是伪共享示意图,下面来解析一下这个伪共享的流程。
伪共享示意图

  • 变量X和Y同时被放到了CPU的一级和二级缓存
  • 当线程1使用CPU1对变量X进行更新时,首先会修改CPU1的一级缓存变量X所在的缓存行,这时在缓存一致性协议(MESI协议1)下,CPU2中变量X对应的缓存航失效。
  • 线程2在写入变量Y时就只能去二级缓存查找,这就破坏了一级缓存。一级缓存比二级缓存更快,这也说明了多个线程不可能同时去修改自己所使用的CPU中相同缓存行里面的变量。
  • 如果CPU只有一级缓存,则会导致频繁地访问主存。

2 为何会出现伪共享

伪共享的产生是因为多个变量被放入了一个缓存行里面,并且多个线程同时去写入缓存行中不同的变量。因为缓存行是Cache与内存交换的基本单位,当CPU要访问的变量没有在缓存行中找到时,根据程序运行的局部性原理,会把该变量所在内存中大小为缓存行的内存放入缓存行。缓存行的大小一般是64个字节。

long a,b,c,d,e,f,g,h;

上述代码声明了8个变量,当CPU访问a的时候,发现该变量没有在缓存中,就会去主内存把a以及内存地址附近的b、c、d、e、f、g、h放入缓存行。也就是地址连续的多个变量才有可能会放到一个缓存行中。

3 如何避免伪共享

3.1 JDK8之前的解决方案

在JDK8之前,一般都是通过字节填充的方式来避免该问题。就是创建一个变量的时候,使用填充字段填充该变量所在的缓存行。

   // jdk7以上使用此方法
   public final static class VolatileLong
    {
        public volatile long value = 0L;
        public long p1, p2, p3, p4, p5, p6;
    }

计算一下,是不是满足64字节?
long类型变量占用8个字节,这里一共7个long类型的变量,总共56字节。VolatileLong是一个类对象,类对象的字节码的对象头占用8个字节,正好64个字节。

3.2 JDK8的解决方案

Java8中已经提供了官方的解决方案,Java8中新增了一个注解:@sun.misc.Contended。加上这个注解的类会自动补齐缓存行,需要注意的是此注解默认是无效的,需要在jvm启动时设置-XX:-RestrictContended才会生效。

   @sun.misc.Contended
   public final static class VolatileLong
    {
        public volatile long value = 0L;
        public long p1, p2, p3, p4, p5, p6;
    }

  1. 在MESI协议中,每个Cache line有4个状态,可用2个bit表示,它们分别是:
    M(Modified):这行数据有效,数据被修改了,和内存中的数据不一致,数据只存在于本Cache中;
    E(Exclusive):这行数据有效,数据和内存中的数据一致,数据只存在于本Cache中;
    S(Shared):这行数据有效,数据和内存中的数据一致,数据存在于很多Cache中;
    I(Invalid):这行数据无效,数据被修改了,和内存中的数据不一致,除去M状态所在的缓存行外,其余的缓存行都失效。 ↩︎

深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值