CppCon 2014 学习:(Costless)Software Abstractions for Parallel Architectures
硬件和科学计算的演变关系:
- 几十年来的硬件进步:计算机硬件不断快速发展,从提升单核速度,到多核并行。
- 科学计算的驱动力:科学计算需求推动硬件创新,比如需要更多计算能力、更高性能。
- 当前的解决方案是并行架构:为了继续提升性能,硬件设计转向多核、多线程、分布式计算等并行体系结构。
- 机器变得越来越复杂:随着并行和异构计算的发展,硬件架构愈加复杂,软件也要适应这种复杂性。
现代硬件复杂性的一个具体例子:
- 硬件背景:过去几十年硬件快速发展,现在科学计算成为推动硬件创新的主要力量。
- 并行架构:为满足计算需求,硬件采用了并行设计。
- 机器复杂性增加:即使是“简单”的笔记本,也包含多种并行技术和硬件加速器。
以这台笔记本为例:
- CPU:Intel Core i5-2410M,主频2.3 GHz,有4个逻辑核心(通常是2物理核+超线程)。
- SIMD扩展:支持SSE2到SSE4.2,AVX(高级向量扩展),能一次处理多个数据,提升单核性能。
- GPU:NVIDIA GeForce GT 520M,有48个CUDA核心,支持GPU并行计算。
总结
这说明现代计算设备包含多层次的并行:
- 多核CPU并行(多线程、多核)
- SIMD指令并行(单指令多数据,向量计算)
- GPU并行(大量小核心,适合大规模并行任务)
计算机硬件和软件的发展阶段,以及随之而来的性能提升和表达能力(expressiveness)变化:
1. 单核时代 (Single Core Era)
- 性能重点:通过提升单核频率和指令集优化来提升性能。
- 代表语言:C、Fortran、C++,多以顺序执行为主。
- 特点:顺序执行,编程相对简单,但性能提升受限于时钟频率。
2. 多核/SIMD时代 (Multi-Core/SIMD Era)
- 性能重点:
- 利用多核并行(线程)
- 利用SIMD指令集(单指令多数据)提高单核效率
- 代表语言:Java(支持多线程和并行模型)
- 特点:
- 需要写并发代码,提高表达能力(expressiveness)以处理线程和数据并行。
- 性能依赖于有效的线程管理和SIMD使用。
3. 异构计算时代 (Heterogeneous Era)
- 性能重点:
- 利用多种并行架构,如GPU、SIMD、Intel Phi(加速器)
- 线程级并行和分布式计算
- 特点:
- 复杂度更高,软件必须支持多种硬件资源
- 分布式系统和异构硬件成为主流,性能提升巨大,但编程复杂度也显著增加。
额外说明:
- 表达能力(Expressiveness):随着硬件复杂度增加,软件需要更丰富的抽象和语言特性来表达并行、异构计算,保证代码可维护和高效执行。
- 你提到的“Sequential”(顺序执行)是在单核时代的标志,后来被多线程和异构计算取代或补充。
科学计算设计工具时面临的挑战和解决思路:
挑战(Challenges)
- 非破坏性(Be non-disruptive)
工具设计要尽量不打断用户已有的工作流程或代码架构,容易集成。 - 领域驱动优化(Domain driven optimizations)
针对具体科学计算领域做专门优化,而不是通用但低效。 - 直观的用户API(Provide intuitive API for the user)
让用户使用简单,易于理解和掌握。 - 支持多样化硬件架构(Support a wide architectural landscape)
适应各种并行硬件和计算平台,比如CPU、GPU、分布式系统等。 - 高效性能(Be efficient)
性能不能妥协,工具必须产生高性能代码。
我们的方案(Our Approach)
- 设计成C++库(Design tools as C++ libraries)
利用C++强大的抽象和性能能力,方便集成且高效。 - 用领域特定嵌入式语言(DSEL)设计库(Design these libraries as Domain Specific Embedded Language)
让库本身像一种专门的语言,提供符合领域思维的表达方式,满足挑战2和3。 - 使用并行骨架(Parallel Skeletons)作为并行组件(Use Parallel Skeletons as parallel components)
抽象并行模式,方便复用和跨平台,实现挑战4。 - 利用生成式编程(Generative Programming)交付性能(Use Generative Programming to deliver performance)
编译期代码生成和模板元编程,最大化运行时效率,满足挑战5。
简单总结:他们选择用C++写一套类似“领域语言”的库,封装并行模式,借助编译期代码生成实现高性能且跨架构的科学计算工具,同时保持易用和兼容性。
**并行骨架(Parallel Skeletons)**的理由,分为软件抽象和硬件抽象两个方面:
为什么用并行骨架(Why using Parallel Skeletons)
1. 软件抽象(Software Abstraction)
- 写代码时不用管并行细节
程序员只需关注算法逻辑,底层的线程、同步、负载均衡等复杂细节被骨架封装。 - 代码可扩展且易维护
代码结构清晰,易于理解和扩展,减少并行代码常见的bug。 - 易调试、可证明、可认证(Debuggable, Provable, Certifiable)
抽象良好,行为可预测,更容易进行形式验证和质量保证。
2. 硬件抽象(Hardware Abstraction)
- 语义固定,具体实现可自由切换
并行骨架定义了高层语义接口,底层可以针对不同硬件(CPU多核、GPU、分布式)选择最佳实现。 - 可组合性 ⇒ 层次化架构(Composability ⇒ Hierarchical architecture)
不同骨架可以组合形成复杂并行模式,支持分层设计,方便构建大型并行系统。
简单来说,并行骨架帮你把复杂的并行编程拆解成易管理、易重用的模块,同时屏蔽硬件细节,写出高效、可维护的并行代码。
这张图片展示了一个由三个主要部分组成的系统架构:领域特定应用程序描述、生成组件和具体应用程序。
- 领域特定应用程序描述:以树形结构表示应用程序的结构,展示特定领域的需求或配置。
- 生成组件:包括“Translator”和“Parametric Sub-components”。Translator负责将领域描述转换为参数化子组件(各种形状),而Parametric Sub-components表示系统中使用的基本构建模块(例如:矩形、圆形、三角形等)。
- 具体应用程序:通过Translator转换后的子组件组合,生成具体的应用程序或结构(例如:复杂的几何形状组合)。
生成式编程(Generative Programming),以及它作为工具的相关技术和定义:
生成式编程作为工具(Generative Programming as a Tool)
可用技术(Available techniques)
- 专用编译器(Dedicated compilers)
设计专门的编译器来支持生成式编程。 - 外部预处理工具(External pre-processing tools)
在编译前对源码做自动生成和转换。 - 支持元编程的语言(Languages supporting meta-programming)
利用语言本身支持的元编程特性来实现代码生成。
元编程定义(Definition of Meta-programming)
- 元编程是编写程序,这些程序可以分析、转换并生成其他程序或自身,以程序作为数据进行操作。
C++元编程(C++ meta-programming)
- 利用C++的**模板子语言(template sub-language)**实现。
- 处理**类型(types)和整数常量(integral constants)**的编译时计算。
- 已被证明是图灵完备的(Turing-complete),也就是说,模板元编程理论上可以完成任何可计算任务。
总结:生成式编程通过元编程技术,实现了在编译期对代码的分析和生成,使得C++代码可以写得更加灵活高效,同时提升性能和表达力。
领域特定嵌入式语言(Domain Specific Embedded Languages, DSEL),主要内容如下:
什么是 DSEL?
- DSL(Domain Specific Language,领域特定语言)
是一种针对特定领域设计的声明式语言,简洁且易用,专门为该领域问题建模。 - DSEL(Domain Specific Embedded Language)
是将DSL嵌入到通用编程语言中的一种技术,比如C++里的DSEL。
C++ 中的 DSEL(EDSL)
- 依赖于运算符重载的“滥用”技术,也就是表达式模板(Expression Templates)。
- 可以在代码片段中携带语义信息,不仅仅是普通的计算,而是让代码本身“懂”它想表达的领域含义。
- 这样泛型实现(Generic implementation)能够自我感知优化机会。
- 利用静态抽象语法树(AST),在编译期对代码进行分析和生成:
- 表达式层面(expression level):进行代码生成
- 函数层面(function level):实现跨函数的优化(inter-procedural optimization)
总结:DSEL 通过嵌入式技术,让开发者用符合领域习惯的方式写代码,同时编译器可以根据这些表达的语义进行高级优化,从而达到高效又易用的目的。
**嵌入式领域特定语言(EDSL)**在C++中的应用,重点和优势如下:
EDSL 在 C++ 中的关键点
- 依赖运算符重载的“滥用”
例如通过 Boost.Proto 库,实现表达式模板的机制,把代码片段当成带语义的信息载体。 - 携带语义信息
代码不仅仅是执行动作,还在类型和表达式结构中携带了领域相关的语义。 - 泛型实现具备“自我感知”的优化能力
因为表达的语义在类型系统中,所以编译期可以根据语义做特定优化。
优势(Advantages)
- 能引入 DSL 而不破坏开发流程
不需要额外的工具链,只用现有的C++编译器和语言特性就能实现领域特定语言。 - 语义定义为类型信息,意味着可以在编译期解决
编译器可以在编译阶段进行静态推导和优化,提升性能和安全性。 - 还可以利用丰富的运行时绑定机制
兼顾灵活性和性能,结合编译期和运行时的优势。
总结:通过 C++ 的 EDSL,开发者可以无缝地在已有C++环境里构建专门领域的语言抽象,既享受DSL的表达简洁性,又保留C++的高性能和工具链兼容性。
表达式模板(Expression Templates) 在矩阵计算中的应用,重点如下:
关键点
- 代码示例:
matrix x(h,w), a(h,w), b(h,w); x = cos(a) + (b * a);
- 编译器不会直接执行普通的逐元素操作,而是构建了一个元表达式树(meta-AST),表示这个计算过程:
expr<assign,expr<matrix&>,expr<plus,expr<cos, expr<matrix&>>,expr<multiplies, expr<matrix&>, expr<matrix&>>>>(x,a,b);
- 这个树可以被编译器/库用来做任意变换,比如:
- 合并计算,减少临时变量
- 调度并行执行(比如用 OpenMP )
- 针对特定硬件做优化
运行时展开示例(伪代码):
#pragma omp parallel for
for(int j=0; j < h; ++j) {for(int i=0; i < w; ++i) {x(j,i) = cos(a(j,i)) + (b(j,i) * a(j,i));}
}
总结
表达式模板通过静态构建表达式树,让编译器能够:
- 避免创建临时矩阵,减少内存开销
- 实现自动向量化、并行化等优化
- 在编译期对代码做重写,提高性能
这是一种非常强大且高效的元编程技术,广泛应用于线性代数库如 Eigen、Blaze 等。
“并行领域专用嵌入式语言(Parallel DSEL)”在实际中的应用,核心内容总结如下:
目标 (Objectives)
- 利用DSEL生成技术,针对不同硬件进行代码生成
- 展示抽象层带来的低性能开销(低成本抽象)
- 演示并行骨架(skeletons)的可用性和效果
贡献 (Our contribution)
- BSP++
通用C++ BSP(Bulk Synchronous Parallel)框架,支持共享内存和分布式内存架构 - Quaff
针对并行骨架编程的领域专用语言 - Boost.SIMD
便携式SIMD编程的DSEL,方便使用SIMD指令集实现向量化 - NT2
类MATLAB的科学计算DSEL,简洁高效,支持向量化和并行化
总结
这些项目结合了DSEL和并行编程技术,解决了如何用高层抽象同时保证效率的问题。它们通过模板元编程和代码生成技术,支持多种硬件,方便科学计算领域的开发者写出高性能且可维护的代码。
NT2,这是一个科学计算库,核心特点总结如下:
NT2 概述
- 科学计算库,目标是简化数值计算,提供类似 MATLAB 的简洁接口
- 高性能:提供高效的计算基本单元和操作原语,保证计算性能
- 易扩展:设计灵活,方便用户和开发者扩展功能
组成部分
- Boost.SIMD
利用Boost.SIMD实现底层向量化优化,充分发挥CPU SIMD指令集优势 - 递归并行骨架
利用并行骨架(parallel skeletons),递归分解任务,实现高效的并行执行 - 架构与运行时无关
代码设计上与硬件架构和具体运行时解耦,提高移植性和灵活性
总结
NT2通过现代C++模板元编程和DSEL技术,将用户友好的接口和底层高性能结合起来,非常适合科研人员和工程师进行大规模科学计算。
The Numerical Template Toolbox (NT2) 的核心设计理念和使用流程:
核心原则
- table<T,S> 类型
一个简单的多维数组类模板,行为和 MATLAB 的数组一模一样 - 丰富的函数库
超过500个函数,既可以作用于 table(数组),也可以作用于标量,接口和 MATLAB 非常接近
使用流程
- 拿一个 MATLAB 的
.m
文件 - 复制改写成
.cpp
文件 - 在代码开头添加:
并做必要的格式(语法)调整#include <nt2/nt2.hpp>
- 编译这个
.cpp
文件并链接到libnt2.a
静态库 - 完成,程序即可高效运行,且几乎和 MATLAB 代码一样简单
总结
NT2 就像是 MATLAB 的 C++ 版本,让用户可以用接近 MATLAB 的风格写高性能 C++ 数值计算程序,兼顾易用性和速度。
这段代码展示了如何用 MATLAB 代码表达数值计算,具体是:
MATLAB代码含义:
A1 = 1:1000; % 生成向量 A1,包含1到1000的整数
A2 = A1 + randn(size(A1)); % A2 = A1 + 正态分布随机噪声,长度与A1相同
X = lu(A1*A1'); % 计算矩阵 A1*A1' 的 LU 分解
rms = sqrt(sum(sqr(A1(:)-A2(:))) / numel(A1)); % 计算 A1 和 A2 差的均方根误差
这里每步操作:
1:1000
生成 1 到 1000 的行向量randn(size(A1))
生成与 A1 同尺寸的正态分布随机值A1*A1'
是向量与其转置的乘积,生成一个 1000×1000 矩阵lu(...)
是矩阵的 LU 分解A1(:)
和A2(:)
都是把矩阵转换成列向量sqr(...)
是逐元素平方sum(...)
是求和numel(A1)
是元素个数,1000sqrt(...)
是平方根
NT2 里写法(伪代码风格)
#include <nt2/nt2.hpp>
nt2::table<double> A1 = nt2::_(1,1000); // 创建1到1000的数组
nt2::table<double> A2 = A1 + nt2::randn(nt2::size(A1)); // 加噪声
auto X = nt2::lu(A1 * nt2::trans(A1)); // LU分解
auto diff = A1 - A2;
double rms = nt2::sqrt(nt2::sum(nt2::sqr(nt2::reshape(diff, nt2::numel(A1), 1))) / nt2::numel(A1));
C++ 代码用 NT2 库,实现了与之前 MATLAB 代码几乎相同的功能。详细说明如下:
table<double> A1 = _(1., 1000.); // 创建一个从1到1000的数组(向量)
table<double> A2 = A1 + randn(size(A1)); // 给A1加上正态随机噪声,生成A2
table<double> X = lu(mtimes(A1, trans(A1))); // 计算A1乘以转置A1的矩阵乘积,并对结果做LU分解
double rms = sqrt(sum(sqr(A1(_) - A2(_))) / numel(A1)); // 计算A1与A2差值的均方根误差
各部分解释:
_(1., 1000.)
:生成从1到1000的数组,类似 MATLAB 的1:1000
。randn(size(A1))
:生成和 A1 同样大小的正态分布随机数组。mtimes(A1, trans(A1))
:矩阵乘法,trans(A1)
是转置。lu(...)
:LU分解函数。A1(_)
、A2(_)
:NT2 里“全部元素”的语法,类似A1(:)
。sqr
:逐元素平方。sum
:求和。numel(A1)
:元素个数。
整体来说:
NT2通过重载操作符和提供类似 MATLAB 的API,让C++也能像MATLAB一样写矩阵和向量运算,且支持高效编译。
Motion Detection
table<char> sigma_delta(table<char>& background, table<char> const& frame, table<char>& variance) {// Estimate Raw Movementbackground = selinc(background < frame, seldec(background > frame, background));table<char> diff = dist(background, frame);// Compute Local Variancetable<char> sig3 = muls(diff, 3);var = if_else(diff != 0, selinc(variance < sig3, seldec(var > sig3, variance)), variance);// Generate Movement Labelreturn if_zero_else_one(diff < variance);
}
这段代码描述的是一个 Sigma-Delta运动检测算法 的 NT2 实现,它是一种用于视频分析的轻量级背景建模方法,适合在低功耗、嵌入式设备中使用(例如机器人视觉、安防监控等)。下面是代码分段讲解:
背景
- 该算法用于检测运动物体。
- 不使用浮点数,仅使用小范围整数(如
char
),以便提升性能并减少资源使用。 - 目标是用 SIMD 向量化库(NT2)进行高效实现。
代码功能分解:
background = selinc( background < frame,seldec(background > frame, background) );
1. 背景模型更新
selinc
/seldec
是 条件自增/自减。background
向当前帧frame
靠拢:- 如果当前帧更亮,则背景变亮;
- 如果当前帧更暗,则背景变暗;
- 这是 Sigma-Delta 的核心建模步骤。
table<char> diff = dist(background, frame);
2. 差值计算
dist
计算每个像素点当前帧与背景之间的差值(绝对值)。
table<char> sig3 = muls(diff,3);
3. 扩大差值
- 将差值乘3,用于调整容差窗口(threshold);
muls
是饱和乘法,防止溢出。
var = if_else( diff != 0,selinc(variance < sig3,seldec(var > sig3, variance)),variance);
4. 更新局部方差(variance)
- 如果有差异(
diff != 0
),则:- 如果当前方差过小,则递增;
- 如果过大,则递减;
- 否则,保持不变。
return if_zero_else_one( diff < variance );
5. 输出运动掩码
- 比较差值是否小于方差(在容差范围内 → 认为是背景);
if_zero_else_one
产生 0/1 掩码(1 表示运动,0 表示无变化)。
总结
步骤 | 含义 |
---|---|
背景建模 | background 向 frame 靠拢 |
差值计算 | 估计当前帧与背景差异 |
方差调整 | 根据信号变化动态调整容差 |
运动检测 | 若变化超出容差,则为“运动” |
该算法结构简单但实用,且易于并行和 SIMD 化,适用于资源受限场景。 |
NT2(Numerical Template Toolbox)库编写的 Black-Scholes 期权定价公式 的两种版本:
- 普通版(直接表达式计算)
- Loop Fusion 优化版(缓存友好、更高性能)
背景:Black-Scholes 模型公式
欧式看涨期权定价公式如下:
C = S ⋅ N ( d 1 ) − X ⋅ e − r T ⋅ N ( d 2 ) C = S \cdot N(d_1) - X \cdot e^{-rT} \cdot N(d_2) C=S⋅N(d1)−X⋅e−rT⋅N(d2)
其中:
d 1 = ln ( S / X ) + ( r + 1 2 v 2 ) T v T , d 2 = d 1 − v T d_1 = \frac{\ln(S/X) + (r + \frac{1}{2}v^2)T}{v\sqrt{T}}, \quad d_2 = d_1 - v\sqrt{T} d1=vTln(S/X)+(r+21v2)T,d2=d1−vT
- S S S: 当前资产价格 (
Sa
) - X X X: 执行价格 (
Xa
) - T T T: 到期时间 (
Ta
) - r r r: 无风险利率 (
ra
) - v v v: 波动率 (
va
) - N ( ⋅ ) N(\cdot) N(⋅): 标准正态累积分布函数 (
normcdf
)
普通版代码:直接链式表达式
table<float> blackscholes(table<float> const& Sa,table<float> const& Xa,table<float> const& Ta,table<float> const& ra,table<float> const& va) {table<float> da = sqrt(Ta);table<float> d1 = log(Sa / Xa) + (sqr(va) * 0.5f + ra) * Ta / (va * da);table<float> d2 = d1 - va * da;return Sa * normcdf(d1) - Xa * exp(-ra * Ta) * normcdf(d2);
}
优点:简洁、可读性强
缺点:每一步可能创建中间临时变量,性能可能受影响,特别是 多次遍历内存,对 CPU cache 不友好。
Loop Fusion 优化版
table<float> blackscholes(table<float> const& Sa, table<float> const& Xa,table<float> const& Ta, table<float> const& ra,table<float> const& va) {// 预分配表(避免反复申请内存)table<float> da(extent(Ta)), d1(extent(Ta)), d2(extent(Ta)), R(extent(Ta));// tie + expression templates 实现 loop fusiontie(da, d1, d2, R) = tie(sqrt(Ta),log(Sa / Xa) + (sqr(va) * 0.5f + ra) * Ta / (va * sqrt(Ta)), // 注意此处da是并行绑定的d1 - va * da,Sa * normcdf(d1) - Xa * exp(-ra * Ta) * normcdf(d2));return R;
}
优化点详解
tie(...) = tie(...)
:- 这是 NT2 的一个 loop fusion 技巧,可以让多个数组的元素计算在一个循环内完成。
- 提高缓存局部性(cache locality)和流水线效率
- 减少临时变量和内存分配开销
- 显式管理中间变量 (
da
,d1
,d2
) 可以在后续重用或进一步优化
总结对比
版本 | 优点 | 缺点 |
---|---|---|
普通表达式 | 简洁、易读 | 中间变量多、可能缓存不友好 |
Loop Fusion | 高性能、单遍多算 | 可读性差一点、维护难度略高 |
如果你想深入实践这个例子,我还可以给你: |
- OpenMP 或 CUDA 后端扩展方式(基于 NT2)
- 对比测试结果模板(性能评估)
- 更详细解释 tie / extent / normcdf 的底层实现
相关文章:

CppCon 2014 学习:(Costless)Software Abstractions for Parallel Architectures
硬件和科学计算的演变关系: 几十年来的硬件进步:计算机硬件不断快速发展,从提升单核速度,到多核并行。科学计算的驱动力:科学计算需求推动硬件创新,比如需要更多计算能力、更高性能。当前的解决方案是并行…...

网络爬虫 - App爬虫及代理的使用(十一)
App爬虫及代理的使用 一、App抓包1. App爬虫原理2. reqable的安装与配置1. reqable安装教程2. reqable的配置3. 模拟器的安装与配置1. 夜神模拟器的安装2. 夜神模拟器的配置4. 内联调试及注意事项1. 软件启动顺序2. 开启抓包功能3. reqable面板功能4. 夜神模拟器设置项5. 注意事…...
Kafka集群部署(docker容器方式)SASL认证(zookeeper)
一、服务器环境 序号 部署版本 版本 1 操作系统 CentOS Linux release 7.9.2009 (Core) 2 docker Docker version 20.10.6 3 docker-compose docker-compose version 1.28.2 二、服务规划 序号 服务 名称 端口 1 zookeeper zookeeper 2181,2888,3888 2 ka…...
【python爬虫】利用代理IP爬取filckr网站数据
亮数据官网链接:亮数据官网...

群晖 NAS 如何帮助培训学校解决文件管理难题
在现代教育环境中,数据管理和协同办公的效率直接影响到教学质量和工作流畅性。某培训学校通过引入群晖 NAS,显著提升了部门的协同办公效率。借助群晖的在线协作、自动备份和快照功能,该校不仅解决了数据散乱和丢失的问题,还大幅节…...

NLP学习路线图(十八):Word2Vec (CBOW Skip-gram)
自然语言处理(NLP)的核心挑战在于让机器“理解”人类语言。传统方法依赖独热编码(One-hot Encoding) 表示单词,但它存在严重缺陷:每个单词被视为孤立的符号,无法捕捉词义关联(如“国…...
P1438 无聊的数列/P1253 扶苏的问题
因为这两天在写线性代数的作业,没怎么写题…… P1438 无聊的数列 题目背景 无聊的 YYB 总喜欢搞出一些正常人无法搞出的东西。有一天,无聊的 YYB 想出了一道无聊的题:无聊的数列。。。 题目描述 维护一个数列 ai,支持两种操…...

嵌入式学习笔记 - 新版Keil软件模拟时钟Xtal灰色不可更改的问题
在新版Keil软件中,模拟时钟无法修改XTAL频率,默认只能使用12MHz时钟。这是因为Keil MDK从5.36版本开始,参数配置界面不再支持修改系统XTAL频率,XTAL选项变为灰色,无法修改。这会导致在软件仿真时出现时间错误的问题&…...
k8s的出现解决了java并发编程胡问题了
Kubernetes(K8s)作为一种开源的容器编排平台,极大地简化了应用程序的部署、管理和扩展。这不仅解决了很多基础设施方面的问题,也间接解决了Java并发编程中的一些复杂问题。本文将详细探讨Kubernetes是如何帮助解决Java并发编程中的…...
如何利用大语言模型生成特定格式文风的报告类文章
在这个算法渗透万物的时代,我们不再仅仅满足于大语言模型(LLM)能“写”,更追求它能“写出精髓,写出风格”。尤其在专业且高度格式化的报告类文章领域,仅仅是内容正确已远远不够,文风的精准复刻才是决定报告是否“对味儿”、能否被目标受众有效接受的关键。这不再是简单的…...

黑马Java面试笔记之 集合篇(算法复杂度+ArrayList+)
一. 算法复杂度分析 1.1 时间复杂度 时间复杂度分析:来评估代码的执行耗时的 常见的复杂度表示形式 常见复杂度 1.2 空间复杂度 空间复杂度全称是渐进空间复杂度,表示算法占用的额外存储空间与数据规模之间的增长关系 二. 数组 数组(Array&a…...
【从0-1的HTML】第2篇:HTML标签
文章目录 1.标题标签2.段落标签3.文本标签brbstrongsubsup 4.超链接标签5.图片标签6.表格标签7.列表标签有序列表ol无序列表ul定义列表dl 8.表单标签9.音频标签10.视频标签11.HTML元素分类块级元素内联元素 12.HTML布局13.内联框架13.内联框架 1.标题标签 标题标签:…...
从“Bucharest”谈起:词语翻译的音译与意译之路
在翻译中,面对地名、人名或新兴术语时,我们常常会遇到一个抉择:到底是“音译”,保留其原发音风貌,还是“意译”,让它意义通达? 今天我们以“Bucharest”为例,展开一次语言与文化的微…...

Nginx+Tomcat负载均衡
目录 Tomcat简介 Tomcat 的核心功能 Tomcat架构 Tomcat 的特点 Tomact配置 关闭防火墙及系统内核 Tomcar 主要文件信息 配置文件说明 案例一:Java的Web站点 案例二:NginxTomcat负载均衡、动静分离 Tomcat简介 Tomcat 是由 Apache 软件基金会&am…...
JVM——JVM中的字节码:解码Java跨平台的核心引擎
引入 在Java的技术版图中,字节码(Bytecode)是连接源代码与机器世界的黄金桥梁。当开发者写下第一行public class HelloWorld时,编译器便开始了一场精密的翻译工程——将人类可读的Java代码转化为JVM能够理解的字节码指令。这些由…...

【论文解读】ReAct:从思考脱离行动, 到行动反馈思考
认识从实践开始,经过实践得到了理论的认识,还须再回到实践去。 ——《实践论》,毛泽东 1st author: About – Shunyu Yao – 姚顺雨 paper [2210.03629] ReAct: Synergizing Reasoning and Acting in Language ModelsReAct: Synergizing Reasoning and…...
数据解析:一文掌握Python库 lxml 的详细使用(处理XML和HTML的高性能库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、lxml 概述1.1 lxml 介绍1.2 安装和第一个案例1.3 性能优化技巧二、XML处理2.1 解析XML2.2 访问元素2.3 遍历XML树2.4 修改XML2.5 写入XML三、HTML处理3.1 解析HTML3.2 XPath查询3.3 CSS选择器四、高级功能4.1 使用命…...
react native webview加载本地HTML,解决iOS无法加载成功问题
在react native中使用 “react-native-webview”: “^13.13.5”,加载HTML文件 Android: 将HTML文件放置到android/src/main/assets目录,访问 {uri: file:///android_asset/markmap/index.html}ios: 在IOS中可以直接可以直接放在react native项目下,访问…...

简单配置RHEL9.X
切换默认运行级别 将系统默认启动模式从多用户的图形界面调整为多用户的文本界面,适用于优化系统资源占用或进行远程服务器管理的场景。 注意:安装选择“带GUI的服务器”部分常用命令默认安装;如果选择“最小安装”时,部分常用命…...
默认网关 -- 负责转发数据包到其他网络的设备(通常是路由器)
✅ 默认网关概括说明: 默认网关(Default Gateway)是网络中一台负责转发数据包到其他网络的设备(通常是路由器)。当一台主机要访问不在本地子网内的设备时,会将数据包发给默认网关,由它继续转发…...
python调用硅基流动的视觉语言模型
参考: https://docs.siliconflow.cn/cn/userguide/capabilities/vision import base64 import json from openai import OpenAI from PIL import Image import io# 初始化OpenAI客户端 client OpenAI(api_key"sk-**********", # 替换为实际API密钥b…...

下载并运行自制RAG框架
项目部署 https://github.com/huangjia2019/rag-project01-framework git clone https://github.com/huangjia2019/rag-project01-framework.git 一 、 前端分部分部署 在 Ubuntu 系统 上安装 Node.js 和 npm(Node Package Manager),并初始…...

Rust 学习笔记:Cargo 工作区
Rust 学习笔记:Cargo 工作区 Rust 学习笔记:Cargo 工作区创建工作区在工作区中创建第二个包依赖于工作区中的外部包向工作区添加测试将工作区中的 crate 发布到 crates.io添加 add_two crate 到工作区总结 Rust 学习笔记:Cargo 工作区 随着项…...

颈部的 “异常坚持”
生活中,有些人的颈部会突然变得 “异常坚持”—— 头部不受控制地偏向一侧,或是不自主地旋转、后仰,仿佛被无形的力量牵引着。这种情况不仅影响外观,还会带来强烈的不适感,颈部肌肉紧绷、酸痛,像被一根绳索…...

Ubuntu22.04安装MinkowskiEngine
MinkowskiEngine简介 Minkowski引擎是一个用于稀疏张量的自动微分库。它支持所有标准神经网络层,例如对稀疏张量的卷积、池化和广播操作。 MinkowskiEngine安装 官方源码链接:GitHub - NVIDIA/MinkowskiEngine: Minkowski Engine is an auto-diff neu…...

【计算机网络】第2章:应用层—应用层协议原理
目录 1. 网络应用的体系结构 2. 客户-服务器(C/S)体系结构 3. 对等体(P2P)体系结构 4. C/S 和 P2P 体系结构的混合体 Napster 即时通信 5. 进程通信 6. 分布式进程通信需要解决的问题 7. 问题1:对进程进行编址…...

【Zephyr 系列 6】使用 Zephyr + BLE 打造蓝牙广播与连接系统(STEVAL-IDB011V1 实战)
🧠关键词:Zephyr、BLE、广播、连接、GATT、低功耗蓝牙、STEVAL-IDB011V1 📌适合人群:希望基于 Zephyr 实现 BLE 通信的嵌入式工程师、蓝牙产品开发人员 🧭 前言:为什么选择 Zephyr 开发 BLE? 在传统 BLE 开发中,我们大多依赖于厂商 SDK(如 Nordic SDK、BlueNRG SD…...

利用 Scrapy 构建高效网页爬虫:框架解析与实战流程
目录 前言1 Scrapy 框架概述1.1 Scrapy 的核心优势1.2 Scrapy 的典型应用场景 2 Scrapy 工作原理解析2.1 框架结构图2.2 Spider:定义数据采集策略2.3 Scheduler:调度请求与去重2.4 Downloader:网页下载器2.5 Item:结构化数据容器2…...

RPG20.创建敌人的初始能力和加载武器
1. 基于StartUpAbilitiy基类创建专门用于敌人数据的DAStartUpABility,然后再基于新创建的DA再创建一个蓝图 2.打开 DataAsset_EnemyStartUpData.h // Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "Cor…...
P5684 [CSP-J2019 江西] 非回文串 题解
https://www.luogu.com.cn/problem/P5684 /* 比较简单的组合计数 题目没有以文字去描述,而是用下标来形式化题意,给我们一个关键信息:判定两个串是否相同不是看字符是否相同,而是看下标 换言之就是相同的字符,如果下标…...