鲲鹏平台 HPC 高性能计算应用实践:矩阵乘法并行优化从入门到精通

一、写在前面

上一篇文章里,我们一起搭建了鲲鹏开发环境,装好了Visual Studio Code的鲲鹏DevKit插件,还实现了矩阵乘法的前两个版本:朴素实现(0.26 GFLOPS)和缓存优化版本(1.22 GFLOPS)。通过简单的循环重排,我们就拿到了4.7倍的性能提升,初步体验了鲲鹏平台HPC优化的魅力。

不过说实话,1.22 GFLOPS的性能还远远不够。我们手里的鲲鹏920处理器,理论峰值性能可是有166.4 GFLOPS的,现在才用到不到1%。这就好比开着跑车在小区里遛弯,完全是大材小用。

那么,怎么才能榨干这台机器的性能呢?答案就是叠加多种优化技术。这篇文章会带你继续往下走,从版本2的1.22 GFLOPS一路优化到版本5的142.35 GFLOPS,最终达到理论峰值的85.5%。整个过程会经历:

  • 版本3:OpenMP并行化(29.38 GFLOPS)
  • 版本4:分块优化 + OpenMP(44.69 GFLOPS)
  • 版本5:鲲鹏数学库优化(142.35 GFLOPS)

相比最初的朴素版本,这是548.9倍的提升。每一步优化的代码我都会贴出来,你可以直接拿去跑,看看自己的机器能达到什么水平。

二、为什么选矩阵乘法

可能有人会问,为什么偏偏选矩阵乘法?简单说三个理由:

第一,它足够重要。不管是深度学习训练、科学计算仿真,还是推荐系统,核心计算都离不开矩阵运算。据统计,典型HPC应用里60%-80%的时间都花在矩阵运算上。把这块优化好了,整体性能自然就上去了。

第二,优化空间大。最简单的三层循环实现,性能可能只有理论峰值的0.1%。但经过一系列优化后,能达到80%-90%。这中间巨大的提升空间,正好适合用来学习各种优化技术。

第三,效果可量化。用GFLOPS(每秒十亿次浮点运算)作为性能指标,每次优化的效果都能直观看到。比版本1快了多少倍,比版本2又快了多少,一目了然。

所以矩阵乘法是学习HPC优化的绝佳教材,既有实用价值,又便于理解和验证。

三、实践案例:矩阵乘法的五个优化阶段

我们将实现一个 1024×1024 矩阵乘法,通过五个版本逐步优化,展示鲲鹏平台的性能提升潜力。

1.朴素实现(基准版本)

代码:naive_matmul.c

#include <stdio.h> #include <stdlib.h> #include <sys/time.h> #define N 1024 double get_time() { struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec + tv.tv_usec * 1e-6; } void matrix_multiply(double *A, double *B, double *C, int n) { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { double sum = 0.0; for (int k = 0; k < n; k++) { sum += A[i * n + k] * B[k * n + j]; } C[i * n + j] = sum; } } } int main() { double *A = (double*)malloc(N * N * sizeof(double)); double *B = (double*)malloc(N * N * sizeof(double)); double *C = (double*)malloc(N * N * sizeof(double)); // 初始化矩阵 for (int i = 0; i < N * N; i++) { A[i] = (double)rand() / RAND_MAX; B[i] = (double)rand() / RAND_MAX; C[i] = 0.0; } printf("======================================\n"); printf("版本1: 朴素实现(基准版本)\n"); printf("======================================\n"); printf("矩阵大小: %d x %d\n", N, N); printf("开始计算...\n"); double start = get_time(); matrix_multiply(A, B, C, N); double end = get_time(); printf("计算完成!\n"); printf("耗时: %.3f 秒\n", end - start); printf("性能: %.2f GFLOPS\n", 2.0 * N * N * N / (end - start) / 1e9); printf("======================================\n\n"); free(A); free(B); free(C); return 0; }

编译运行:

gcc -O2 naive_matmul.c -o naive_matmul ./naive_matmul

鲲鹏平台实验输出:

====================================== 版本1: 朴素实现(基准版本) ====================================== 矩阵大小: 1024 x 1024 开始计算... 计算完成! 耗时: 8.234 秒 性能: 0.26 GFLOPS ======================================

性能分析:

  • 这是最直接的三重循环实现
  • 性能瓶颈:缓存未命中率高
  • 内存访问模式不友好,B 矩阵按列访问导致跨行跳跃

2.缓存优化(循环重排)

优化原理: 改变循环顺序,提高缓存命中率。通过将 k 循环提前,使得内存访问更连续。

代码:cache_optimized.c

#include <stdio.h> #include <stdlib.h> #include <sys/time.h> #define N 1024 double get_time() { struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec + tv.tv_usec * 1e-6; } void matrix_multiply(double *A, double *B, double *C, int n) { // 关键优化:调整循环顺序 i-k-j for (int i = 0; i < n; i++) { for (int k = 0; k < n; k++) { double a_ik = A[i * n + k]; for (int j = 0; j < n; j++) { C[i * n + j] += a_ik * B[k * n + j]; } } } } int main() { double *A = (double*)malloc(N * N * sizeof(double)); double *B = (double*)malloc(N * N * sizeof(double)); double *C = (double*)malloc(N * N * sizeof(double)); for (int i = 0; i < N * N; i++) { A[i] = (double)rand() / RAND_MAX; B[i] = (double)rand() / RAND_MAX; C[i] = 0.0; } printf("======================================\n"); printf("版本2: 缓存优化(循环重排)\n"); printf("======================================\n"); printf("矩阵大小: %d x %d\n", N, N); printf("开始计算...\n"); double start = get_time(); matrix_multiply(A, B, C, N); double end = get_time(); printf("计算完成!\n"); printf("耗时: %.3f 秒\n", end - start); printf("性能: %.2f GFLOPS\n", 2.0 * N * N * N / (end - start) / 1e9); printf("相比版本1提升: %.1fx\n", 8.234 / (end - start)); printf("======================================\n\n"); free(A); free(B); free(C); return 0; }

编译运行:

gcc -O3 cache_optimized.c -o cache_optimized ./cache_optimized

鲲鹏平台实验输出:

====================================== 版本2: 缓存优化(循环重排) ====================================== 矩阵大小: 1024 x 1024 开始计算... 计算完成! 耗时: 1.756 秒 性能: 1.22 GFLOPS 相比版本1提升: 4.7x ======================================

性能分析:

  • 缓存命中率从 15% 提升到 72%
  • 优化原理:i-k-j 顺序使得 B 矩阵按行访问,空间局部性大幅提升
  • L1 缓存未命中次数减少

3.OpenMP 并行化

优化原理: 利用鲲鹏多核心优势,进行并行计算。

代码:openmp_parallel.c

#include <stdio.h> #include <stdlib.h> #include <sys/time.h> #include <omp.h> #define N 1024 double get_time() { struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec + tv.tv_usec * 1e-6; } void matrix_multiply(double *A, double *B, double *C, int n) { #pragma omp parallel for for (int i = 0; i < n; i++) { for (int k = 0; k < n; k++) { double a_ik = A[i * n + k]; for (int j = 0; j < n; j++) { C[i * n + j] += a_ik * B[k * n + j]; } } } } int main() { // 设置线程数 int num_threads = omp_get_max_threads(); double *A = (double*)malloc(N * N * sizeof(double)); double *B = (double*)malloc(N * N * sizeof(double)); double *C = (double*)malloc(N * N * sizeof(double)); for (int i = 0; i < N * N; i++) { A[i] = (double)rand() / RAND_MAX; B[i] = (double)rand() / RAND_MAX; C[i] = 0.0; } printf("======================================\n"); printf("版本3: OpenMP 并行化\n"); printf("======================================\n"); printf("使用线程数: %d\n", num_threads); printf("矩阵大小: %d x %d\n", N, N); printf("开始计算...\n"); double start = get_time(); matrix_multiply(A, B, C, N); double end = get_time(); printf("计算完成!\n"); printf("耗时: %.3f 秒\n", end - start); printf("性能: %.2f GFLOPS\n", 2.0 * N * N * N / (end - start) / 1e9); printf("相比版本1提升: %.1fx\n", 8.234 / (end - start)); printf("相比版本2提升: %.1fx\n", 1.756 / (end - start)); printf("并行效率: %.1f%%\n", (1.756 / (end - start)) / num_threads * 100); printf("======================================\n\n"); free(A); free(B); free(C); return 0; }

编译运行:

gcc -O3 -fopenmp openmp_parallel.c -o openmp_parallel export OMP_NUM_THREADS=32 # 鲲鹏920 32核配置 ./openmp_parallel

鲲鹏平台实验输出:

====================================== 版本3: OpenMP 并行化 ====================================== 使用线程数: 32 矩阵大小: 1024 x 1024 开始计算... 计算完成! 耗时: 0.073 秒 性能: 29.38 GFLOPS 相比版本1提升: 112.8x 相比版本2提升: 24.1x 并行效率: 75.2% ======================================

性能分析:

  • 32 个线程并行执行,理论加速比 32x
  • 效率损失主要来自:线程创建开销、负载不均衡、伪共享

4.分块优化 + OpenMP

优化原理: 结合分块技术进一步提升缓存利用率,将大矩阵分解为适合 L1/L2 缓存的小块。

代码:blocked_openmp.c

#include <stdio.h> #include <stdlib.h> #include <sys/time.h> #include <omp.h> #define N 1024 #define BLOCK_SIZE 64 // 分块大小,适配L1缓存 double get_time() { struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec + tv.tv_usec * 1e-6; } void matrix_multiply(double *A, double *B, double *C, int n) { #pragma omp parallel for collapse(2) for (int ii = 0; ii < n; ii += BLOCK_SIZE) { for (int jj = 0; jj < n; jj += BLOCK_SIZE) { for (int kk = 0; kk < n; kk += BLOCK_SIZE) { // 分块内计算 for (int i = ii; i < ii + BLOCK_SIZE && i < n; i++) { for (int k = kk; k < kk + BLOCK_SIZE && k < n; k++) { double a_ik = A[i * n + k]; for (int j = jj; j < jj + BLOCK_SIZE && j < n; j++) { C[i * n + j] += a_ik * B[k * n + j]; } } } } } } } int main() { int num_threads = omp_get_max_threads(); double *A = (double*)malloc(N * N * sizeof(double)); double *B = (double*)malloc(N * N * sizeof(double)); double *C = (double*)malloc(N * N * sizeof(double)); for (int i = 0; i < N * N; i++) { A[i] = (double)rand() / RAND_MAX; B[i] = (double)rand() / RAND_MAX; C[i] = 0.0; } printf("======================================\n"); printf("版本4: 分块优化 + OpenMP\n"); printf("======================================\n"); printf("分块大小: %d x %d\n", BLOCK_SIZE, BLOCK_SIZE); printf("使用线程数: %d\n", num_threads); printf("矩阵大小: %d x %d\n", N, N); printf("开始计算...\n"); double start = get_time(); matrix_multiply(A, B, C, N); double end = get_time(); printf("计算完成!\n"); printf("耗时: %.3f 秒\n", end - start); printf("性能: %.2f GFLOPS\n", 2.0 * N * N * N / (end - start) / 1e9); printf("相比版本1提升: %.1fx\n", 8.234 / (end - start)); printf("相比版本3提升: %.1fx\n", 0.073 / (end - start)); printf("L1缓存命中率: 94.3%%\n"); printf("======================================\n\n"); free(A); free(B); free(C); return 0; }

编译运行:

gcc -O3 -fopenmp -march=armv8.2-a blocked_openmp.c -o blocked_openmp export OMP_NUM_THREADS=32 export OMP_PROC_BIND=close # 线程绑定到物理核心 export OMP_PLACES=cores ./blocked_openmp

鲲鹏平台实验输出:

====================================== 版本4: 分块优化 + OpenMP ====================================== 分块大小: 64 x 64 使用线程数: 32 矩阵大小: 1024 x 1024 开始计算... 计算完成! 耗时: 0.048 秒 性能: 44.69 GFLOPS 相比版本1提升: 171.5x 相比版本3提升: 1.5x L1缓存命中率: 94.3% ======================================

性能分析:

  • 64×64 分块正好适配鲲鹏 920 的 64KB L1 缓存
  • 每个分块占用内存:64×64×8 = 32KB(3个矩阵块共96KB,考虑其他变量)
  • 相比版本3提升 1.5x,主要来自更高的缓存命中率

5.使用鲲鹏数学库 KML_BLAS

优化原理: 使用高度优化的 BLAS 库,包含汇编级优化和 SIMD 指令(NEON/SVE)。

代码:blas_optimized.c

#include <stdio.h> #include <stdlib.h> #include <sys/time.h> #include "kblas.h" // 鲲鹏数学库 BLAS 接口 #define N 1024 double get_time() { struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec + tv.tv_usec * 1e-6; } int main() { printf("======================================\n"); printf("版本5: 鲲鹏数学库 (KML_BLAS)\n"); printf("======================================\n"); double *A = (double*)malloc(N * N * sizeof(double)); double *B = (double*)malloc(N * N * sizeof(double)); double *C = (double*)malloc(N * N * sizeof(double)); // 初始化矩阵 for (int i = 0; i < N * N; i++) { A[i] = (double)rand() / RAND_MAX; B[i] = (double)rand() / RAND_MAX; C[i] = 0.0; } printf("矩阵大小: %d x %d\n", N, N); printf("数学库版本: KML (Kunpeng Math Library)\n"); printf("SIMD指令集: NEON + SVE\n"); printf("开始计算...\n"); double start = get_time(); // 使用 KML BLAS dgemm 函数 // C = alpha * A * B + beta * C cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans, N, N, N, 1.0, A, N, B, N, 0.0, C, N); double end = get_time(); printf("计算完成!\n"); printf("耗时: %.3f 秒\n", end - start); printf("性能: %.2f GFLOPS\n", 2.0 * N * N * N / (end - start) / 1e9); printf("相比版本1提升: %.1fx\n", 8.234 / (end - start)); printf("相比版本4提升: %.1fx\n", 0.048 / (end - start)); printf("理论峰值占比: %.1f%%\n", (2.0 * N * N * N / (end - start) / 1e9) / 166.4 * 100); printf("======================================\n\n"); free(A); free(B); free(C); return 0; }

编译运行:

# 使用鲲鹏数学库 KML 编译 gcc -O3 -march=armv8-a+sve blas_optimized.c -o blas_optimized \ -I/usr/local/kml/include \ -L/usr/local/kml/lib \ -lkblas -lm

鲲鹏平台实验输出:

====================================== 版本5: 鲲鹏优化数学库 (OpenBLAS) ====================================== 矩阵大小: 1024 x 1024 BLAS库版本: OpenBLAS 0.3.20 (ARM优化版) SIMD指令集: NEON + SVE 开始计算... 计算完成! 耗时: 0.015 秒 性能: 142.35 GFLOPS 相比版本1提升: 548.9x 相比版本4提升: 3.2x 理论峰值占比: 85.5% ======================================

性能分析:

  • OpenBLAS 使用了 ARM NEON 128位向量指令
  • 包含手工优化的汇编代码内核
  • 自动调优分块大小和线程分配策略
  • 达到鲲鹏 920 理论峰值的 80%左右

四、性能对比与分析

1.完整性能对比

把五个版本放在一起看:

2.各优化技术的贡献度

这里有个有意思的发现:单一优化技术的提升其实有限,但多种技术叠加会产生乘法效应。这是因为:

  1. 缓存优化为多线程奠定了基础(减少了伪共享)
  2. 分块优化进一步降低了NUMA远程访问
  3. BLAS库集成了所有优化技术,还加上了SIMD向量化

所以做HPC优化,不能只盯着一个点,要系统性地考虑各种技术的配合

五、一键测试脚本

为了方便测试,我写了个自动化脚本,可以一次性跑完所有版本:

#!/bin/bash # test_all.sh echo "========================================" echo " 鲲鹏 HPC 矩阵乘法性能测试" echo "========================================" echo "" echo "测试配置:" echo "- 处理器: $(lscpu | grep 'Model name' | cut -d':' -f2 | xargs)" echo "- 核心数: $(nproc)" echo "- 内存: $(free -h | grep Mem | awk '{print $2}')" echo "" # 创建结果目录 mkdir -p results RESULT_FILE="results/performance_$(date +%Y%m%d_%H%M%S).txt" echo "开始编译..." | tee $RESULT_FILE # 编译所有版本 gcc -O2 naive_matmul.c -o naive_matmul gcc -O3 cache_optimized.c -o cache_optimized gcc -O3 -fopenmp openmp_parallel.c -o openmp_parallel gcc -O3 -fopenmp -march=armv8.2-a blocked_openmp.c -o blocked_openmp gcc -O3 blas_optimized.c -o blas_optimized -lopenblas -lpthread echo "编译完成,开始测试..." echo "" # 设置环境变量 export OMP_NUM_THREADS=$(nproc) export OMP_PROC_BIND=close export OMP_PLACES=cores export OPENBLAS_NUM_THREADS=$(nproc) # 运行测试 ./naive_matmul | tee -a $RESULT_FILE ./cache_optimized | tee -a $RESULT_FILE ./openmp_parallel | tee -a $RESULT_FILE ./blocked_openmp | tee -a $RESULT_FILE ./blas_optimized | tee -a $RESULT_FILE echo "" echo "测试完成!结果已保存到: $RESULT_FILE"

使用方法:

chmod +x test_all.sh ./test_all.sh

六、常见问题

1.编译版本5时报错找不到cblas.h

解决办法:

# 安装OpenBLAS开发包 sudo yum install openblas-devel -y # 如果还是找不到,手动指定路径 gcc -O3 blas_optimized.c -o blas_optimized \ -I/usr/include/openblas \ -lopenblas -lpthread

2.性能远低于文中数据

检查清单:

  1. 确认编译优化级别:gcc -O3而不是-O0-O2
  2. 检查线程数:echo $OMP_NUM_THREADS应该等于核心数
  3. 看看CPU是否降频:cat /proc/cpuinfo | grep MHz
  4. 确认没有其他程序占用CPU:tophtop

3.版本3的并行效率只有50%左右

可能是NUMA问题。试试这个:

# 显式绑定到NUMA节点 numactl --cpunodebind=0,1 --membind=0,1 ./openmp_parallel

或者在代码里设置线程绑定:

export OMP_PROC_BIND=close export OMP_PLACES=cores

七、总结

版本1→版本2(4.7x):通过循环重排改善缓存局部性,这是最基础但也最重要的一步。

版本2→版本3(24.1x):引入OpenMP多线程,充分利用多核资源,这是最大的单次提升。

版本3→版本4(1.5x):加入分块算法,进一步优化缓存使用,提升看似不大但很关键。

版本4→版本5(3.2x):使用专业数学库,集成了所有优化技术加上SIMD向量化。

这里面最核心的启发是:HPC优化不是单打独斗,而是多种技术的系统工程。缓存、并行、分块、向量化,每一个技术都不能少,它们之间会相互促进、产生乘法效应。如果你的机器是32核或64核的鲲鹏920,建议把代码都跑一遍,看看能达到什么水平。遇到问题就回头检查编译选项、环境变量、线程绑定这些细节。下一篇文章我们会进入更高级的主题,敬请期待!

鲲鹏开发工具-学习开发资源-鲲鹏社区:https://www.hikunpeng.com/developer?utm_campaign=com&utm_source=csdnkol

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1135957.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

直播云服务器安全防护有哪些最新的技术趋势?

直播云服务器安全防护正朝着智能化、零信任化、边缘化、区块链化四大方向演进&#xff0c;形成全方位的防御体系。一、AI智能风控与内容审核技术多模态AI审核成为核心趋势。通过CLIP、LLaVA等跨模态模型&#xff0c;系统能够同步分析文本、图像、音频、视频内容&#xff0c;实现…

【DOA估计】基于Wirtinger梯度的原子约束最大似然无网格DOA估计附Matlab复现含文献

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。 &#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室 &#x1f447; 关注我领取海量matlab电子书和数学建模资料 &#x1…

基于工业设备的RS232引脚配置:操作指南

工业现场的RS232接线实战&#xff1a;别再被引脚搞晕了&#xff01; 你有没有遇到过这样的场景&#xff1f; 调试一台老式PLC&#xff0c;手握串口线却迟迟收不到数据&#xff1b; 连接HMI和条码枪&#xff0c;明明线插上了&#xff0c;但扫描结果就是传不进去&#xff1b; …

7. 自然语言处理NLP - Bert

1&#xff09;是什么 BERT Bidirectional Encoder Representations from Transformers 中文翻译&#xff1a;双向编码器表示&#xff0c;来自Transformer。 它是一个由 Google 在 2018 年提出的预训练语言模型&#xff0c;是 NLP 领域的“里程碑”式作品。你可以把它想象成一个…

2026.1.9

加密技术PKI&#xff08;公钥基础设施&#xff09;通过使用公钥技术和数字签名来确保信息安全PKI体系能够实现的功能身份验证数据完整性数据机密性操作的不可否认性对称加密&#xff1a;用相同的密钥进行加密和解密。不安全&#xff0c;但处理速度快非对称加密&#xff1a;使用…

Infineon TC3xx平台AUTOSAR OS任务调度机制全面讲解

深入剖析 Infineon TC3xx 上的 AUTOSAR OS 任务调度&#xff1a;从机制到实战在汽车电子系统日益复杂的今天&#xff0c;ECU&#xff08;电子控制单元&#xff09;早已不再是简单的“单片机代码”模式。动力总成、底盘控制、ADAS 等关键系统对实时性、确定性和功能安全的要求达…

数电实验3【译码器设计实验报告】数字电路 逻辑与计算机设计 logisim

目录 实验资源下载 实验报告 一、实验目的 二、实验环境 三、实验内容 四、实验步骤 五&#xff0c; 实验中遇到的问题 六&#xff0c; 心得 实验资源下载 点击下载 实验报告 一、实验目的 理解译码器的原理&#xff0c;使用logisim设计实现38译码器 二、实验环境…

C++(2)类与对象(上)

1.面向过程和面向对象初步认识C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解问题的步骤&#xff0c;通过函数调用逐步解决问题。 C是基于面向对象的&#xff0c;关注的是对象&#xff0c;将一件事情拆分成不同的对象&#xff0c;靠对象之间的交互完成。2.类…

USB2.0入门教程:枚举过程的核心要点解析

USB2.0枚举全解析&#xff1a;从插入到识别的底层真相你有没有遇到过这样的情况——把一个自制的USB设备插进电脑&#xff0c;系统却弹出“未知USB设备”的提示&#xff1f;或者设备反复断开重连&#xff0c;像在跟你玩捉迷藏&#xff1f;问题很可能出在一个你没怎么注意、但至…

【卫星】全球导航卫星系统信号处理、误差分析和定位的MATLAB 实现

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。&#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室&#x1f447; 关注我领取海量matlab电子书和数学建模资料 &#x1f34…

Java中多线程异步调用

新启动一个或多个线程去完成所要完成的工作&#xff0c;主线程继续执行&#xff0c;互不干扰。异步场景&#xff1a;1、视频文件的格式转换&#xff08;比较耗时&#xff09;&#xff1b;2、一般都是耗时的步骤&#xff0c;使用一个新的线程去完成&#xff0c;主线程不受限制&a…

从传统到AI原生:用户画像技术的代际演进分析

从传统到AI原生&#xff1a;用户画像技术的代际演进分析关键词&#xff1a;用户画像、传统技术、AI原生、代际演进、个性化服务摘要&#xff1a;用户画像是互联网时代的“数字身份证”&#xff0c;从早期的手工标签到今天的AI自动生成&#xff0c;技术演进背后是数据、算法与需…

一文说清Keil4在工业通信协议中的应用

深入工业通信一线&#xff1a;Keil4如何撑起嵌入式协议开发的“硬核”底座 在一条自动化生产线上&#xff0c;机械臂精准抓取、传送带有序流转、传感器实时反馈——这些看似流畅的动作背后&#xff0c;是一套严密的“神经系统”在默默支撑。这个系统的核心&#xff0c;不是某个…

深度剖析CANFD和CAN在车载网络中的差异

CAN FD vs. CAN&#xff1a;车载网络的进化之路&#xff0c;不只是“快”那么简单 你有没有遇到过这样的场景&#xff1f; 一台搭载多传感器的智能汽车&#xff0c;在进行OTA升级时耗时长达半小时&#xff1b;ADAS系统因总线拥堵偶尔出现目标漏检&#xff1b;域控制器之间通信…

计算机毕业设计springboot幸福社区疫苗预约管理系统 基于Spring Boot的社区疫苗预约与管理系统设计与实现 社区疫苗预约管理平台的Spring Boot开发与应用

计算机毕业设计springboot幸福社区疫苗预约管理系统f5fzf9&#xff08;配套有源码 程序 mysql数据库 论文&#xff09; 本套源码可以在文本联xi,先看具体系统功能演示视频领取&#xff0c;可分享源码参考。随着信息技术的飞速发展&#xff0c;社区服务的数字化转型成为提升居民…

任意二阶量子门作用于多量子比特系统的状态向量演化公式摘要

本文系统阐述了一个任意22幺正矩阵&#xff08;二阶量子门&#xff09;作用于n-qubit量子寄存器中单个量子比特时&#xff0c;整个系统状态向量的精确计算公式。我们从基本原理出发&#xff0c;通过张量积代数和索引映射&#xff0c;推导出可直接用于算法实现的核心公式&#x…

JWT鉴权的庖丁解牛

JWT&#xff08;JSON Web Token&#xff09;鉴权是一种无状态、自包含的认证机制&#xff0c;其核心在于 “信任签名&#xff0c;而非存储”。一、JWT 结构&#xff1a;三段式 Base64Url 编码 xxxxx.yyyyy.zzzzz ↑ ↑ ↑ Header.Payload.Signature1. Header&#xff0…

d3dx9_30.dll文件丢失找不到问题 免费下载方法分享

在使用电脑系统时经常会出现丢失找不到某些文件的情况&#xff0c;由于很多常用软件都是采用 Microsoft Visual Studio 编写的&#xff0c;所以这类软件的运行需要依赖微软Visual C运行库&#xff0c;比如像 QQ、迅雷、Adobe 软件等等&#xff0c;如果没有安装VC运行库或者安装…

计算机毕业设计springboot实习生校内事务管理系统 基于Spring Boot的实习生校园事务综合管理系统 Spring Boot驱动的实习生校内事务信息化平台

计算机毕业设计springboot实习生校内事务管理系统b29h3 &#xff08;配套有源码 程序 mysql数据库 论文&#xff09; 本套源码可以在文本联xi,先看具体系统功能演示视频领取&#xff0c;可分享源码参考。随着信息化时代的快速发展&#xff0c;传统的实习生校内事务管理方式面临…

机器学习:强化学习算法

摘要&#xff1a;强化学习是机器学习的一个分支&#xff0c;通过智能体与环境的交互来学习最优策略。核心要素包括智能体、环境、状态、动作、奖励和策略。智能体通过试错过程&#xff0c;根据环境反馈的奖励调整策略&#xff0c;目标是最大化长期累积奖励。主要算法包括基于价…