并发程序的隐藏杀手你知道是谁吗?

C++ std::async 五大核心陷阱与最佳实践:从并发利器到性能杀手 在现代C++并发编程中,异步任务执行是提升程序性能的关键技术。其核心原理是通过将计算任务分配到不同线程,实现CPU资源的并行利用,从而缩短整体执行时间。这项技术的核心价值在于简化多线程编程模型,提高开发效率,尤其适用于I/O密集型操作、并行计算和后台任务处理等场景。然而,若使用不当,异步编程反而会成为性能瓶颈和稳定性隐患。本文聚焦于C++标准库中的 `std::async` 函数,深入剖析其因默认启动策略不确定性导致的**线程阻塞**问题,以及因 `future` 对象析构行为引发的**资源泄漏**风险。通 阅读详情

假共享(False Sharing)

缓存行

当CPU从更慢级别的缓存读取数据的时候(三级Cache会从内存当中读取数据,二级缓存会从三级缓存当中读取数据,一级缓存会从二级缓存当中读取数据,缓存级别越低执行速度越快),CPU并不是一个字节一个字节的读取的,而是一次会读取一块数据,然后将这个数据缓存到CPU当中,而这一块数据就叫做缓存行。有一种缓存行的大小就是64字节,那么我们为什么会做这种优化呢?这是因为局部性原理,所谓局部性原理简单说来就是,当时使用一个数据的时候,它附近的数据在未来的一段时间你也很可能用到,比如说我们遍历数组,我们通常从前往后进行遍历,比如我们数组当中的数据大小是8个字节,如果我们的缓存行是64个字节的话,那么一个缓存行就可以缓存8个数据,那么我们在遍历第一个数据的时候将这8个数据加载进入缓存行,那么我们在遍历未来7个数据的时候都不需要再从内存当中拿数据,直接从缓存当中拿就行,这就可以节约程序执行的时间。

假共享

当两个线程在CPU上两个不同的核心上执行代码的时候,如果这两个线程使用了同一个缓存行C,而且对这个缓存行当中两个不同的变量进行写操作,比如线程A对变量a进行写操作,线程B对变量b进行写操作。而由于缓存一致性(Cache coherence)协议的存在,如果其中A线程对缓存行C中变量a进行了写操作的话,为了保证各个CPU核心的数据一致(也就是说两个CPU核心看到了a的值是一样的,因为a的值已经发生变化了,需要让另外的CPU核心知道,不然另外的CPU核心使用的就是旧的值,那么程序结果就不对了),其他核心的这个缓存行就会失效,如果他还想使用这个缓存行的话就需要重新三级Cache加载,如果数据不存在三级Cache当中的话,就会从内存当中加载,而这个重新加载的过程就会很拖累程序的执行效率,而事实上线程A写的是变量a,线程B写的是变量b,他们并没有真正的有共享的数据,只是他们需要的数据在同一个缓存行当中,因此称这种现象叫做假共享(False Sharing)。

当缓存行失效的时候会从三级Cache或者内存当中加载,而多个不同的CPU核心是共享三级Cache的(上图当中已经显示出来了),其中一个CPU核心更新了数据,会把数据刷新到三级Cache或者内存当中,因此这个时候其他的CPU核心去加载数据的时候就是新值了。

我们再来举一个更加具体的例子:

假设在内存当中,变量a和变量b都占四个字节,而且他们的内存地址是连续且相邻的,现在有两个线程A和B,线程A要不断的对变量a进行+1操作,线程B需要不断的对变量进行+1操作,现在这个两个数据所在的缓存行已经被缓存到三级缓存了。

  • 线程A从三级缓存当中将数据加载到二级缓存和一级缓存然后在CPU- Core0当中执行代码,线程B从三级缓存将数据加载到二级缓存和一级缓存然后在CPU- Core1当中执行代码。
  • 线程A不断的执行a += 1,因为线程B缓存的缓存行当中包含数据a,线程A在修改a的值之后,就会在总线上发送消息,让其他处理器当中含有变量a的缓存行失效,在处理器将缓存行失效之后,就会在总线上发送消息,表示缓存行已经失效,线程A所在的CPU- Core0收到消息之后将更新后的数据刷新到三级Cache。
  • 这个时候线程B所在的CPU-Core1当中含有a的缓存行已经失效,因为变量b和变量a在同一个缓存行,现在线程B想对变量b进行加一操作,但是在一级和二级缓存当中已经没有了,它需要三级缓存当中加载这个缓存行,如果三级缓存当中没有就需要去内存当中加载。
  • 仔细分析上面的过程你就会发现线程B并没有对变量a有什么操作,但是它需要的缓存行就失效了,虽然和线程B共享需要同一个内容的缓存行,但是他们之间并没有真正共享数据,所以这种现象叫做假共享。

Java代码复现假共享

复现假共享

下面是两个线程不断对两个变量执行++操作的代码:

class Data {
  public volatile long a;
  public volatile long b;
}

public class FalseSharing {
  public static void main(String[] args) throws InterruptedException {
    Data data = new Data();
    long start = System.currentTimeMillis();
    Thread A = new Thread(() -> {
      for (int i = 0;  i < 500_000_000; i++) {
        data.a += 1;
      }
    }, "A");

    Thread B = new Thread(() -> {
      for (int i = 0;  i < 500_000_000; i++) {
        data.b += 1;
      }
    }, "B");
    A.start();
    B.start();
    A.join();
    B.join();
    long end = System.currentTimeMillis();
    System.out.println("花费时间为:" + (end - start));
    System.out.println(data.a);
    System.out.println(data.b);
  }
}

上面的代码比较简单,这里就不进行说明了,上面的代码在我的笔记本上的执行时间大约是17秒。

上面的代码变量a和变量b在内存当中的位置是相邻的,他们在被CPU加载之后会在同一个缓存行当中,因此会存在假共享的问题,程序的执行时间会变长。

下面的代码是优化过后的代码,在变量a前面和后面分别加入56个字节的数据,再加上a的8个字节(long类型是8个字节),这样a前后加上a的数据有64个字节,而现在主流的缓存行是64个字节,够一个缓存行的大小,因为数据a和数据b就不会在同一个缓存行当中,因此就不会存在假共享的问题了。而下面的代码在我笔记本当中执行的时间大约为5秒。这就足以看出假共享会对程序的执行带来多大影响了。

class Data {
  public volatile long a1, a2, a3, a4, a5, a6, a7;
  public volatile long a;
  public volatile long b1, b2, b3, b4, b5, b6, b7;
  public volatile long b;
}

public class FalseSharing {
  public static void main(String[] args) throws InterruptedException {
    Data data = new Data();
    long start = System.currentTimeMillis();
    Thread A = new Thread(() -> {
      for (int i = 0;  i < 500_000_000; i++) {
        data.a += 1;
      }
    }, "A");

    Thread B = new Thread(() -> {
      for (int i = 0;  i < 500_000_000; i++) {
        data.b += 1;
      }
    }, "B");
    A.start();
    B.start();
    A.join();
    B.join();
    long end = System.currentTimeMillis();
    System.out.println("花费时间为:" + (end - start));
    System.out.println(data.a);
    System.out.println(data.b);
  }
}

JDK解决假共享

为了解决假共享的问题,JDK为我们提供了一个注解@Contened解决假共享的问题。

import sun.misc.Contended;

class Data {
//  public volatile long a1, a2, a3, a4, a5, a6, a7;
  @Contended
  public volatile long a;
//  public volatile long b1, b2, b3, b4, b5, b6, b7;
  @Contended
  public volatile long b;
}

public class FalseSharing {
  public static void main(String[] args) throws InterruptedException {
    Data data = new Data();

    long start = System.currentTimeMillis();
    Thread A = new Thread(() -> {
      for (long i = 0;  i < 500_000_000; i++) {
        data.a += 1;
      }
    }, "A");

    Thread B = new Thread(() -> {
      for (long i = 0;  i < 500_000_000; i++) {
        data.b += 1;
      }
    }, "B");
    A.start();
    B.start();
    A.join();
    B.join();
    long end = System.currentTimeMillis();
    System.out.println("花费时间为:" + (end - start));
    System.out.println(data.a);
    System.out.println(data.b);
  }
}

上面代码的执行时间也是5秒左右,和之前我们自己在变量的左右两边插入变量的效果是一样的,但是JDK提供的这个接口和我们自己实现的还是有所区别的。(注意:上面的代码是在JDK1.8下执行的,如果要想@Contended注解生效,你还需要在JVM参数上加入-XX:-RestrictContended,这样上面的代码才能生效否则是不能够生效的)

  • 在我们自己解决假共享的代码当中,是在变量a的左右两边加入56个字节的其他变量,让他和变量b不在同一个缓存行当中。

  • 在JDK给我们提供的注解@Contended,是在被加注解的字段的右边加入一定数量的空字节,默认加入128空字节,那么变量a和变量b之间的内存地址大一点,最终不在同一个缓存行当中。这个字节数量可以使用JVM参数-XX:ContendedPaddingWidth=64,进行控制,比如这个是64个字节。

  • 除此之外@Contended注解还能够将变量进行分组:

class Data {
  @Contended("a")
  public volatile long a;

  @Contended("bc")
  public volatile long b;
  @Contended("bc")
  public volatile long c;
}

在解析注解的时候会让同一组的变量在内存当中的位置相邻,不同的组之间会有一定数量的空字节,配置方式还是跟上面一样,默认每组之间空字节的数量为128。

比如上面的变量在内存当中的逻辑布局详细布局如下:

 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           20 0a 06 00 (00100000 00001010 00000110 00000000) (395808)
     12   132        (alignment/padding gap)                  
    144     8   long Data.a                                    0
    152   128        (alignment/padding gap)                  
    280     8   long Data.b                                    0
    288     8   long Data.c                                    0
    296   128        (loss due to the next object alignment)
Instance size: 424 bytes
Space losses: 260 bytes internal + 128 bytes external = 388 bytes total

上面的内容是通过下面代码打印的,你只要在pom文件当中引入包jol即可:

import org.openjdk.jol.info.ClassLayout;
import sun.misc.Contended;

class Data {
  @Contended("a")
  public volatile long a;

  @Contended("bc")
  public volatile long b;
  @Contended("bc")
  public volatile long c;
}

public class FalseSharing {
  public static void main(String[] args) throws InterruptedException {
    Data data = new Data();

    System.out.println(ClassLayout.parseInstance(data).toPrintable());
  }
}

从更低层次C语言看假共享

前面我们是使用Java语言去验证假共享,在本小节当中我们通过一个C语言的多线程程序(使用pthread)去验证假共享。(下面的代码在类Unix系统都可以执行)

#include <stdio.h>
#include <pthread.h>
#include <time.h>

#define CHOOSE // 这里定义了 CHOOSE 如果不想定义CHOOSE 则将这一行注释掉即可

// 定义一个全局变量
int data[1000];

void* add(void* flag) {
  // 这个函数的作用就是不断的往 data 当中的某个数据进行加一操作
  int idx = *((int *)flag);
  for (long i = 0; i < 10000000000; ++i) {
    data[idx]++;
  }
}

int main() {
  pthread_t a, b;
#ifdef CHOOSE // 如果定义了 CHOOSE 则执行下面的代码 让两个线程操作的变量隔得远一点 让他们不在同一个缓存行当中
  int flag_a = 0;
  int flag_b = 100;
  printf("远离\n");
#else // 如果没有定义 让他们隔得近一点 也就是说让他们在同一个缓存行当中
  int flag_a = 0;
  int flag_b = 1;
  printf("临近\n");
#endif
  pthread_create(&a, NULL, add, &flag_a); // 创建线程a 执行函数 add 传递参数 flag_a 并且启动
  pthread_create(&b, NULL, add, &flag_b); // 创建线程b 执行函数 add 传递参数 flag_b 并且启动
  long start = time(NULL);
  pthread_join(a, NULL); // 主线程等待线程a执行完成
  pthread_join(b, NULL); // 主线程等待线程b执行完成
  long end = time(NULL);
  printf("data[0] = %d\t data[1] = %d\n", data[0], data[1]);
  printf("cost time = %ld\n", (end - start));
  return 0;
}

上面代码的输出结果如下图所示:

我们首先来解释一下上面time命令的输出:

  • readl:这个表示真实世界当中的墙钟时间,就是表示这个程序执行所花费的时间,这个秒单位和我们平常说的秒是一样的。
  • user:这个表示程序在用户态执行的CPU时间,CPU时间和真实时间是不一样的,这里需要注意区分,这里的秒和我们平常的秒是不一样的。
  • sys:这个表示程序在内核态执行所花费的CPU时间。

从上面程序的输出结果我们可以很明显的看出来当操作的两个整型变量相隔距离远的时候,也就是不在同一个缓存行的时候,程序执行的速度是比数据隔得近在同一个缓存行的时候快得多,这也从侧面显示了假共享很大程度的降低了程序执行的效率。

总结

在本篇文章当中主要讨论了以下内容:

  • 当多个线程操作同一个缓存行当中的多个不同的变量时,虽然他们事实上没有对数据进行共享,但是他们对同一个缓存行当中的数据进行修改,而由于缓存一致性协议的存在会导致程序执行的效率降低,这种现象叫做假共享。
  • 在Java程序当中我们如果想让多个变量不在同一个缓存行当中的话,我们可以在变量的旁边通过增加其他变量的方式让多个不同的变量不在同一个缓存行。
  • JDK也为我们提供了Contended注解可以在字段的后面通过增加空字节的方式让多个数据不在同一个缓存行,而且你需要在JVM参数当中加入-XX:-RestrictContended,同时你可以通过JVM参数-XX:ContendedPaddingWidth=64调整空字节的数目。JDK8之后注解Contended在JDK当中的位置有所变化,大家可以查询一下。
  • 我们也是用了C语言的API去测试了假共享,事实上在Java虚拟机当中底层的线程也是通过调用pthread_create进行创建的。
现代C++性能优化实战:内存管理与并发编程核心技术解析 在计算机科学中,内存管理与并发编程是构建高性能系统的两大基石。内存管理决定了数据在存储介质中的组织与访问效率,其核心原理在于优化数据的空间与时间局部性,以提升CPU缓存命中率,从而突破“内存墙”瓶颈。并发编程则旨在充分利用多核处理器资源,通过合理的任务调度与数据同步机制,将理论算力转化为实际吞吐量。这两项技术的工程价值在于,它们直接决定了软件在数据密集型与计算密集型场景下的响应速度与资源利用率。无论是高并发服务器、实时数据处理系统还是游戏引擎,高效的内存访问模式与稳健的线程协调都是实现低延迟与高扩展性的关键 阅读详情

相关推荐

Tracy Profiler:实时可视化剖析C++多线程程序性能瓶颈

性能分析是软件开发中定位和优化瓶颈的关键环节,其核心原理在于监控程序运行时资源消耗与执行路径。传统采样分析工具虽能提供宏观热点视图,但在诊断多线程并发场景下的锁竞争、线程阻塞等复杂时序问题时往往力不从心。Tracy Profiler 通过创新的手动插桩与实时流式传输机制,实现了低开销、高精度的并发性能剖析,其技术价值在于将抽象的线程交互转化为直观的时间线可视化,让开发者能直接观察锁持有、线程等待等微观事件。这一特性使其特别适用于游戏引擎、高频交易系统等对延迟敏感的实时应用场景,能有效诊断传统工具难以捕捉的间

angou6476的博客 428

并发刺客(False Sharing)——并发程序的隐藏杀手

前段时间在各种社交平台“雪糕刺客”这个词比较火,简单的来说就是雪糕的价格非常高!其实在并发程序当中也有一个刺客,如果在写并发程序的时候不注意不小心,这个刺客很可能会拖累我们的并发程序,让我们并发程序执行的效率变低,让并发程序付出很大的代价,这和“雪糕刺客”当中的“刺客”的含义是一致的。这个并发程序当中的刺客就是——假共享(False Sharing)。...

m0_73311735的博客 169

C++ CPU 缓存一致性与伪共享(False Sharing):并发性能杀手与优化

CPU缓存就像CPU的小金库,把常用的数据放进去,CPU要用的时候直接从金库里拿,速度嗖嗖的!这样,两个线程表面上操作的是不同的数据,实际上却在争夺同一个缓存行,导致大量的缓存同步操作,性能大幅下降。好了,现在每个CPU都有自己的小金库了,问题来了:如果多个CPU同时修改同一个数据,那大家的金库里的数据就不一样了,乱套了!它就像警察叔叔一样,负责维持各个缓存之间的数据一致性,保证大家看到的数据都是最新的。如果你使用的是数组,可以尝试重新排列数组元素的顺序,使频繁访问的元素位于相邻的位置,减少缓存行的争用。

weixin_41455464的博客 507

ConcurrentHashMap扩容机制详解:为什么你的Java并发程序突然变慢了?

本文深入解析了ConcurrentHashMap的扩容机制,揭示了其为何会成为Java并发程序性能突然下降的“隐形杀手”。文章详细阐述了扩容触发的复杂条件、多线程协作迁移的精妙设计,并重点分析了扩容期间导致CPU缓存失效、锁竞争加剧及写操作延迟等性能瓶颈根源。最后,提供了预先规划合理容量、监控诊断以及考虑替代方案等实战优化策略,帮助开发者规避性能风险。

hp777的博客 444

并发编程的潜在威胁:虚假共享

虚假共享是并发编程中的一个潜在威胁,可能导致程序性能下降。虽然现代计算机体系结构中的缓存一致性协议能够保证数据的一致性,但频繁的缓存行无效化和重新加载会带来性能损失。通过使用填充来增加数据项之间的间隔,我们可以避免虚假共享问题,提高并发程序的性能。以上是关于虚假共享的详细介绍和解决方案,并提供了相应的源代码示例。在实际开发中,开发人员应该注意并发程序中的虚假共享问题,并根据具体情况采取相应的解决方案,以提高程序的性能和可靠性。

git_web425的博客 123

AD21导出gerber文件

文件–>制造输出–>Gerber Files 文件–>制造输出–>Gerber Files 通用、光圈和高级跟第一步一样 3.文件–>制造输出–>NC Drill Files 这个默认就可以了 主要参考视频来自bilibili添加链接描述 此篇博客主要是写给自己好记的,无其他商业用途 ...

新手小杨 1万+

深入 JUC 入门核心:Java 多线程上下文切换全解析——性能杀手的识别、测量与优化(Java 实习生必修课)

上下文切换(Context Switch)是指CPU 从一个线程(或进程)切换到另一个线程执行时,保存当前线程的状态(上下文),并加载下一个线程的状态的过程。📌上下文(Context)包含通用寄存器(如 EAX, EBX…)程序计数器(PC)栈指针(SP)状态寄存器(Flags)内存管理信息(页表基址、TLB 状态等)上下文切换是连接操作系统理论与Java 并发实践的关键桥梁。上下文切换的本质:寄存器、缓存、TLB 的保存与恢复;触发机制:自愿 vs 非自愿切换;性能影响。

吾为热爱计科,致力于知识分享的践行者,此博客是我在这条道路上留下的足迹。 874

基于COMSOL电弧动态仿真模型优化:高收敛性可修改吹弧方案解析

在多物理场耦合分析中,电弧动态仿真历来是数值稳定性的难点:温度从室温跃升至数万开尔文,电导率随温度呈数量级跳变,流动、传热与电磁场相互牵制,极易引发求解器不收敛或初始值不一致等问题。如何构建高收敛性的数值模型,成为开关设备灭弧性能优化的重要技术基础。通过合理的几何简化、全耦合求解器配置、辅助扫描初始化策略以及参数化建模手段,可以实现对吹弧方案的灵活调整与批量寻优,从而系统性评估气流速度、喷口形状、触头间距等关键因素对熄弧性能的影响。这类仿真方法广泛应用于断路器、接触器等高压电器产品研发,为灭弧室结构设计提供

weixin_29758911的博客 350

gh_mirrors/ja/javamtp源码中的设计模式陷阱与避坑指南

gh_mirrors/ja/javamtp是《Java多线程编程实战指南(设计模式篇)》的配套源码,包含12个多线程设计模式的实战案例。本文将深入剖析源码中常见的设计模式陷阱,提供实用避坑指南,帮助开发者正确应用多线程设计模式。 ## 线程安全陷阱:从非线程安全到安全实现 多线程环境下,线程安全是首要考虑的问题。源码中明确展示了线程安全与非线程安全的实现对比: - **非线程安全实现**:[

gitblog_00762的博客 270

AI影像组学在结直肠癌诊疗中的应用:从特征提取到临床决策

影像组学通过高通量计算从医学影像中提取定量特征,揭示肿瘤内部的微观生物学行为,这些特征反映了纹理异质性、形状不规则度等影像表型。其核心原理在于将图像数据转化为可分析的数字特征,结合机器学习算法进行模式识别,从而实现对疾病状态的精准预测。这一技术的价值在于能够无创、定量地评估肿瘤特性,为精准医疗提供关键支持。在临床实践中,AI驱动的影像组学模型广泛应用于结直肠癌的诊疗全链条,包括肿瘤良恶性鉴别、基因突变预测、治疗反应评估和预后分析等场景。通过整合影像组学特征与临床数据,可以构建预测模型,辅助医生进行更准确的诊

weixin_28295799的博客 409

3D数学-动力学

3D数学-11-动力学 旋转运动学 二维旋转动力学 首先我们考虑最简单的情况: 我们将F施加在圆盘(忽略质量)上的一个点(质量为m)上 图中:F为我们施加的力,O是枢轴原点。 通过基本的运算,我们可以得到 F'= F*sinθ 那么切向加速度 a = F'/ m 切向加速度是线性速度的加速度,我们通过除以半径获得角加速度 α = a / r 现在,我们换一种方式,那就是通过杠杆臂的方式去施加力 为了能够计算出m点的角加速度,我们需要引入一个概念:扭矩 他的理解类似于力矩,公式如下 τ = Flsi

韩天衣的博客 2285

从崩溃到丝滑:Java 并发编程的 5个致命陷阱与破局指南

从无锁状态到偏向锁,再到轻量级锁,最后到重量级锁,JVM 会根据竞争激烈程度自动调整锁状态,在保证线程安全的同时最大限度提升性能。其中,偏向锁通过消除无竞争情况下的同步开销,轻量级锁通过自旋避免线程阻塞,显著优化了低竞争场景的性能。当新任务提交时,线程池会优先创建核心线程,核心线程满后将任务放入队列,队列满后创建非核心线程,最后当线程数达到最大线程数且队列已满时,触发拒绝策略。记住,最好的并发方案是 “避免不必要的并发”,在设计阶段就考虑线程安全,远比后期修复问题更高效。

weixin_44075173的博客 839

Cadence笔记--原理图导入PCB

根据PCB尺寸画PCB外观尺寸,这里注意X\Y不能超过指定的区域,X\Y的最大值在setuo的grids里设置,画完后保存并关闭工程然后重新打开(不理解为何)由于只画了一个PMU6050,所以这里只有一个器件。工程选择board,选择存储路径和名称。6、重新网格导入,保证网表导入无误;注意网表保存的路径。

weixin_51418325的博客 1954

claude-mem 工作原理深度解析:工具调用如何沉淀为跨会话自动注入的记忆

claude-mem 是一款为 Agent(Claude Code、Codex、Gemini、OpenClaw 等)提供**跨会话持久上下文**的记忆层:它把会话中每一次工具调用捕获并压缩为 observation,在会话结束时汇总结论,并在下一次会话启动时把相关记忆自动注入提示词。本文以 [plugin/skills/how-it-works/onboarding-explainer.md](h

gitblog_00014的博客 423

使用IGV软件可视化染色质可及性

染色质可及性(chromatin accessibility)是指DNA序列在植物细胞核中的可访问程度。染色质是由DNA和蛋白质组成的复杂结构,它紧密地包裹在细胞核中,并影响基因的表达和功能。染色质可及性研究着重于理解染色质是否容易被转录因子和其他调控蛋白访问,从而影响基因的表达。文献中,常常会有下面这种图片来表示基因组上的一些区域或基因的染色质开放性强弱。一般情况下,我们可以使用IGV软件或GSA-man软件进行可视化,两者的操作相似。这里,以IGV软件为例,演示如何对染色质可及性进行可视化。

沉香best的博客 3723

手把手教你学simulink(26.8)--控制算法场景示例:基于强化学习的无人机姿态稳定控制系统

首先,我们需要定义无人机的姿态稳定控制环境。环境包括无人机的状态(姿态角、角速度等)和动作(电机转速)。我们还需要定义奖励函数,用于评估控制器的表现。matlab深色版本% 定义环境% 定义状态空间% 12个状态变量% 定义动作空间% 电机转速范围奖励函数用于评估控制器的表现。我们可以根据无人机的姿态误差、角速度误差以及控制输入的变化率来设计奖励函数。具体来说,当无人机的姿态接近设定值时,给予正奖励;当姿态误差较大或控制输入变化剧烈时,给予负奖励。matlab深色版本。

MHD0815的博客 494

“代码没错就是慢?”——一次 Java 并发踩坑引发的性能深挖

摘要:本文揭示了一个常见的Java并发性能问题——伪共享(False Sharing)。通过示例代码展示了两个线程分别自增独立volatile变量时出现的性能下降现象,解释其成因是CPU缓存行机制导致无关变量的缓存互相影响。文章深入分析了MESI缓存一致性协议和volatile的双重作用,并提供了三种解决方案:手动填充变量、使用@Contended注解以及变量隔离存储。该问题隐蔽性强但对性能影响巨大,开发者需要理解底层硬件机制才能编写高效的并发程序。

m0_74023628的博客 2278

[RK3568 Android12] 添加自定义启动脚本

1:定义添加的脚本 2:rk3568_s.mk 中定义打包 3:在启动脚本中init.rk356x.rc添加权限及何时启动 4:添加权限文件file_contexts 5:系统确认是否运行

OpenWrt/WLAN/驱动/Android/嵌入式开发总结 2219

百万架构师成长之路(3):深入计算机底层:操作系统与网络如何塑造你的上层建筑

真正的系统性能瓶颈往往隐藏于底层硬件和操作系统机制中,包括:1. CPU缓存体系与伪共享问题对并发性能的影响;2. I/O模型从BIO到AIO的演进及Netty的优化策略;3. TCP协议细节(如三次握手、Nagle算法、拥塞控制)对微服务通信的制约;4. 容器技术底层实现(Namespace、Cgroups、UnionFS)的资源隔离原理。

weixin_42680912的博客 675

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Java高并发编程核心场景解析:从实际场景到面试攻略

高并发编程是Java开发者技术体系中的重要组成部分,也是大厂面试的重点考察领域。通过深入理解这些核心场景,不仅能够解决实际开发中的问题,也能为技术成长打下坚实基础。

x1ao_fe1的博客 857

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

为什么你的嵌入式程序总是崩溃?深度剖析C语言进程异常退出原因

深入解析嵌入式 Linux 的 C 语言进程异常退出原因,涵盖内存泄漏、信号处理与资源竞争等常见问题。适用于物联网、工业控制等场景,提供高效调试方法与稳定运行策略。排查崩溃难题一文掌握,值得收藏。

ProceSeed的博客 795

深度学习工具包 DeepLearningToolbox

深度学习工具包Deprecation notice.-----This toolbox is outdated and no longer maintained.There are much better tools available for deep learning than this toolbox, e.g. [Theano](http://deeplearning.net/software/theano/), [torch](http://torch.ch/) or [tensorflow](http://www.tensorflow.org/)I would suggest you use one of the tools mentioned above rather than use this toolbox.Best, Rasmus.DeepLearnToolbox================A Matlab toolbox for Deep Learning.Deep Learning is a new subfield of machine learning that focuses on learning deep hierarchical models of data.It is inspired by the human brain's apparent deep (layered, hierarchical) architecture.A good overview of the theory of Deep Learning theory is[Learning Deep Architectures for AI](http://www.iro.umontreal.ca/~bengioy/papers/ftml_book.pdf)For a more informal introduction, see the following videos by Geoffrey Hinton and Andrew Ng.* [The Next Generation of Neural Networks](http://www.youtube.com/watch?v=AyzOUbkUf3M) (Hinton, 2007)* [Recent Developments in Deep Learning](http://www.youtube.com/watch?v=VdIURAu1-aU) (Hinton, 2010)* [Unsupervised Feature Learning and Deep Learning](http://www.youtube.com/watch?v=ZmNOAtZIgIk) (Ng, 2011)If you use this toolbox in your research please cite [Prediction as a candidate for learning deep hierarchical models of data](http://www2.imm.dtu.dk/pubdb/views/publication_details.php?id=6284)```@MASTERSTHESIS\{IMM2012-06284, author = "R. B. Palm", title = "Prediction as a candidate for learning deep hierarchical models of data", year = "2012",}```Contact: rasmusbergpalm at gmail dot comDirectories included in the toolbox-----------------------------------`NN/` - A library for Feedforward Backpropagation Neural Networks`CNN/` - A library for Convolutional Neural Networks`DBN/` - A library for Deep Belief Networks`SAE/` - A library for Stacked Auto-Encoders`CAE/` - A library for Convolutional Auto-Encoders`util/` - Utility functions used by the libraries`data/` - Data used by the examples`tests/` - unit tests to verify toolbox is workingFor references on each library check REFS.mdSetup-----1. Download.2. addpath(genpath('DeepLearnToolbox'));Example: Deep Belief Network---------------------```matlabfunction test_example_DBNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit RBM and visualize its weightsrand('state',0)dbn.sizes = [100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);figure; visualize(dbn.rbm{1}.W'); % Visualize the RBM weights%% ex2 train a 100-100 hidden unit DBN and use its weights to initialize a NNrand('state',0)%train dbndbn.sizes = [100 100];opts.numepochs = 1;opts.batchsize = 100;opts.momentum = 0;opts.alpha = 1;dbn = dbnsetup(dbn, train_x, opts);dbn = dbntrain(dbn, train_x, opts);%unfold dbn to nnnn = dbnunfoldtonn(dbn, 10);nn.activation_function = 'sigm';%train nnopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.10, 'Too big error');```Example: Stacked Auto-Encoders---------------------```matlabfunction test_example_SAEload mnist_uint8;train_x = double(train_x)/255;test_x = double(test_x)/255;train_y = double(train_y);test_y = double(test_y);%% ex1 train a 100 hidden unit SDAE and use it to initialize a FFNN% Setup and train a stacked denoising autoencoder (SDAE)rand('state',0)sae = saesetup([784 100]);sae.ae{1}.activation_function = 'sigm';sae.ae{1}.learningRate = 1;sae.ae{1}.inputZeroMaskedFraction = 0.5;opts.numepochs = 1;opts.batchsize = 100;sae = saetrain(sae, train_x, opts);visualize(sae.ae{1}.W{1}(:,2:end)')% Use the SDAE to initialize a FFNNnn = nnsetup([784 100 10]);nn.activation_function = 'sigm';nn.learningRate = 1;nn.W{1} = sae.ae{1}.W{1};% Train the FFNNopts.numepochs = 1;opts.batchsize = 100;nn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.16, 'Too big error');```Example: Convolutional Neural Nets---------------------```matlabfunction test_example_CNNload mnist_uint8;train_x = double(reshape(train_x',28,28,60000))/255;test_x = double(reshape(test_x',28,28,10000))/255;train_y = double(train_y');test_y = double(test_y');%% ex1 Train a 6c-2s-12c-2s Convolutional neural network %will run 1 epoch in about 200 second and get around 11% error. %With 100 epochs you'll get around 1.2% errorrand('state',0)cnn.layers = { struct('type', 'i') %input layer struct('type', 'c', 'outputmaps', 6, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %sub sampling layer struct('type', 'c', 'outputmaps', 12, 'kernelsize', 5) %convolution layer struct('type', 's', 'scale', 2) %subsampling layer};cnn = cnnsetup(cnn, train_x, train_y);opts.alpha = 1;opts.batchsize = 50;opts.numepochs = 1;cnn = cnntrain(cnn, train_x, train_y, opts);[er, bad] = cnntest(cnn, test_x, test_y);%plot mean squared errorfigure; plot(cnn.rL);assert(er<0.12, 'Too big error');```Example: Neural Networks---------------------```matlabfunction test_example_NNload mnist_uint8;train_x = double(train_x) / 255;test_x = double(test_x) / 255;train_y = double(train_y);test_y = double(test_y);% normalize[train_x, mu, sigma] = zscore(train_x);test_x = normalize(test_x, mu, sigma);%% ex1 vanilla neural netrand('state',0)nn = nnsetup([784 100 10]);opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samples[nn, L] = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.08, 'Too big error');%% ex2 neural net with L2 weight decayrand('state',0)nn = nnsetup([784 100 10]);nn.weightPenaltyL2 = 1e-4; % L2 weight decayopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex3 neural net with dropoutrand('state',0)nn = nnsetup([784 100 10]);nn.dropoutFraction = 0.5; % Dropout fraction opts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex4 neural net with sigmoid activation functionrand('state',0)nn = nnsetup([784 100 10]);nn.activation_function = 'sigm'; % Sigmoid activation functionnn.learningRate = 1; % Sigm require a lower learning rateopts.numepochs = 1; % Number of full sweeps through dataopts.batchsize = 100; % Take a mean gradient step over this many samplesnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex5 plotting functionalityrand('state',0)nn = nnsetup([784 20 10]);opts.numepochs = 5; % Number of full sweeps through datann.output = 'softmax'; % use softmax outputopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, train_x, train_y, opts);[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');%% ex6 neural net with sigmoid activation and plotting of validation and training error% split training data into training and validation datavx = train_x(1:10000,:);tx = train_x(10001:end,:);vy = train_y(1:10000,:);ty = train_y(10001:end,:);rand('state',0)nn = nnsetup([784 20 10]); nn.output = 'softmax'; % use softmax outputopts.numepochs = 5; % Number of full sweeps through dataopts.batchsize = 1000; % Take a mean gradient step over this many samplesopts.plot = 1; % enable plottingnn = nntrain(nn, tx, ty, opts, vx, vy); % nntrain takes validation set as last two arguments (optionally)[er, bad] = nntest(nn, test_x, test_y);assert(er < 0.1, 'Too big error');```[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/rasmusbergpalm/deeplearntoolbox/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

`C++编程艺术从代码优化到性能提升的深度探索`

错误共享是并发程序中常见的性能杀手,当多个线程频繁修改位于同一缓存行的不同变量时,会导致缓存行在各核之间无效化,产生大量不必要的缓存同步。但需要注意的是,无锁并非总是更快,在低竞争情况下,基于互斥锁的方案可能更简单且性能相当。例如,将频繁访问的数据组织在连续内存中,使用std::vector替代std::list,或者通过数据对齐确保关键数据结构跨越缓存行边界的最小次数。例如,在实现树结构时,B树通常比二叉树具有更好的缓存性能,因为它的节点大小与缓存行对齐,每次访问能加载更多相关数据。

u012381565的博客 467

Java并发——并发编程底层原理

并发编程的底层,是操作系统和硬件精心编排的一场“时间分片”大戏。时间片轮转让我们在单核时代体验到“并行”的错觉,上下文切换则保证多任务公平执行的同时,也带来了性能损耗。了解这些底层机制,我们才能在实际开发中更理性地设计并发策略:既充分利用多核资源,又避免过度切换带来的开销。

2301_82251392的博客 286

C++并发编程实战:从标准库原语到性能优化避坑指南

并发编程是现代软件开发的核心技术,它允许多个任务同时执行,从而提升系统吞吐量和响应速度。其基本原理是通过线程、进程或协程实现任务并行,并借助同步原语(如互斥锁、条件变量)协调共享资源访问,避免数据竞争。这项技术的核心价值在于充分利用多核CPU性能,构建高性能、高响应的应用系统,广泛应用于服务器开发、图形处理、科学计算等场景。在实际工程中,线程池是管理并发任务的常见模式,它能有效复用线程资源,避免频繁创建销毁的开销;而锁竞争则是性能优化的关键挑战,需要通过减小锁粒度、使用读写锁或无锁数据结构来缓解。本文基于经

weixin_34378969的博客 391
上一篇: Lightrun还可以这样用?
下一篇: Java加密算法有几种?
Java_ttcd
博客等级 码龄4年 198粉丝 190原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值