当前位置: 首页 > news >正文

高效并发编程:无锁编程

无锁编程是一种并发编程的技术,旨在避免使用传统的锁机制来保护共享数据。相比有锁编程,无锁编程可以提供更高的并发性能和可伸缩性。在无锁编程中,线程或进程通过使用原子操作、CAS(Compare-and-Swap)等技术来实现对共享数据的访问和修改,而不需要依赖互斥锁。

无锁编程常用于高并发场景,如网络服务器、多线程应用程序等。它可以减少线程之间的竞争和阻塞,并且能够充分利用多核处理器的计算能力。然而,由于无锁编程对开发者要求较高,在设计和实现上也更加复杂,需要考虑线程安全性、内存模型等因素。

一、无锁编程概述

1.1什么是无锁编程

无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Synchronization),实现非阻塞同步的方案称为“无锁编程算法”。

为什么要非阻塞同步,使用lock实现线程同步有非常多缺点:

  • 产生竞争时,线程被阻塞等待,无法做到线程实时响应

  • dead lock

  • live lock

  • 优先级反转

  • 使用不当,造成性能下降

假设在不使用 lock 的情况下,实现变量同步,那就会避免非常多问题。尽管眼下来看,无锁编程并不能替代 lock。

实现级别

非同步阻塞的实现分为三个级别:wait-free/lock-free/obstruction-free

(1)wait-free

  • 最理想的模式,整个操作保证每一个线程在有限步骤下完毕

  • 保证系统级吞吐(system-wide throughput)以及无线程饥饿

  • 截止2011年,没有多少详细的实现。即使实现了,也须要依赖于详细CPU

(2)lock-free

  • 同意个别线程饥饿,但保证系统级吞吐。

  • 确保至少有一个线程可以继续运行。

  • wait-free的算法必然也是lock-free的。

(3)obstruction-free

在不论什么时间点,一个线程被隔离为一个事务进行运行(其它线程suspended),而且在有限步骤内完毕。在运行过程中,一旦发现数据被改动(採用时间戳、版本),则回滚,也叫做乐观锁,即乐观并发控制(OOC)。

事务的过程是:

  • 读取,并写时间戳

  • 准备写入,版本号校验

  • 检验通过则写入,检验不通过,则回滚

lock-free必然是obstruction-free的。

1.2为什么要无锁?

首先是性能考虑。通信项目一般对性能有极致的追求,这是我们使用无锁的重要原因。当然,无锁算法如果实现的不好,性能可能还不如使用锁,所以我们选择比较擅长的数据结构和算法进行lock-free实现,比如Queue,对于比较复杂的数据结构和算法我们通过lock来控制,比如Map(虽然我们实现了无锁Hash,但是大小是限定的,而Map是大小不限定的),对于性能数据,后续文章会给出无锁和有锁的对比。

次要是避免锁的使用引起的错误和问题:

  • 死锁(dead lock):两个以上线程互相等待

  • 锁护送(lock convoy):多个同优先级的线程反复竞争同一个锁,抢占锁失败后强制上下文切换,引起性能下降

  • 优先级反转(priority inversion):低优先级线程拥有锁时被中优先级的线程抢占,而高优先级的线程因为申请不到锁被阻塞。

1.3如何无锁?

在现代的 CPU 处理器上,很多操作已经被设计为原子的,比如对齐读(Aligned Read)和对齐写(Aligned Write)等。Read-Modify-Write(RMW)操作的设计让执行更复杂的事务操作变成了原子操作,当有多个写入者想对相同的内存进行修改时,保证一次只执行一个操作。

RMW 操作在不同的 CPU 家族中是通过不同的方式来支持的:

  • x86/64 和 Itanium 架构通过 Compare-And-Swap (CAS) 方式来实现

  • PowerPC、MIPS 和 ARM 架构通过 Load-Link/Store-Conditional (LL/SC) 方式来实现

在x64下进行实践的,用的是CAS操作,CAS操作是lock-free技术的基础,我们可以用下面的代码来描述:

template <class T>
bool CAS(T* addr, T expected, T value)
{
  if (*addr == expected)
  {
     *addr = value;
     return true;
  }
  return false;
}

 在GCC中,CAS操作如下所示:

bool __sync_bool_compare_and_swap (type *ptr, type oldval type newval, ...)
type __sync_val_compare_and_swap (type *ptr, type oldval type newval, ...)

这两个函数提供原子的比较和交换,如果*ptr == oldval,就将newval写入*ptr,第一个函数在相等并写入的情况下返回true,第二个函数的内置行为和第一个函数相同,只是它返回操作之前的值。 

后面的可扩展参数(...)用来指出哪些变量需要memory barrier,因为目前gcc实现的是full barrier,所以可以略掉这个参数,除过CAS操作,GCC还提供了其他一些原子操作,可以在无锁算法中灵活使用:

type __sync_fetch_and_add (type *ptr, type value, ...)
type __sync_fetch_and_sub (type *ptr, type value, ...)
type __sync_fetch_and_or (type *ptr, type value, ...)
type __sync_fetch_and_and (type *ptr, type value, ...)
type __sync_fetch_and_xor (type *ptr, type value, ...)
type __sync_fetch_and_nand (type *ptr, type value, ...)

type __sync_add_and_fetch (type *ptr, type value, ...)
type __sync_sub_and_fetch (type *ptr, type value, ...)
type __sync_or_and_fetch (type *ptr, type value, ...)
type __sync_and_and_fetch (type *ptr, type value, ...)
type __sync_xor_and_fetch (type *ptr, type value, ...)
type __sync_nand_and_fetch (type *ptr, type value, ...) 

_sync_*系列的built-in函数,用于提供加减和逻辑运算的原子操作。这两组函数的区别在于第一组返回更新前的值,第二组返回更新后的值。

无锁算法感触最深的是复杂度的分解,比如多线程对于一个双向链表的插入或删除操作,如何能一步一步分解成一个一个串联的原子操作,并能保证事务内存的一致性。

 1.4从传统到无锁:编程范式的转变

在并发编程的世界中,传统的锁编程曾是保障数据一致性和线程安全的中流砥柱 。就像在一场热闹的集市中,每个摊位是一个共享资源,而锁就是摊位的钥匙,线程则是想要使用摊位的商人。当一个商人拿到钥匙(获取锁)后,就能在摊位上自由交易(访问和修改资源),其他商人只能在一旁等待,直到钥匙被归还(锁被释放)。

这种方式虽然有效,但在多线程高并发的场景下,却逐渐暴露出诸多局限性。

线程阻塞是最直观的问题。当一个线程持有锁时,其他试图获取同一锁的线程就会被阻塞,进入等待状态。这就好比多个商人都想使用同一个摊位,但只有一个人能拿到钥匙,其他人只能干等着,白白浪费时间。在高并发系统中,大量线程的阻塞会导致上下文切换频繁,极大地消耗系统资源,降低了程序的执行效率 。

死锁隐患更是让人头疼。想象一下,两个商人 A 和 B,A 拿着摊位 1 的钥匙,却想要使用摊位 2;B 拿着摊位 2 的钥匙,却想要使用摊位 1。双方都不愿意放弃自己手中的钥匙,又都在等待对方释放钥匙,结果就陷入了僵局,谁也无法继续。在编程中,死锁一旦发生,程序就会陷入停滞,无法正常运行,严重影响系统的稳定性 。

传统锁编程还会带来较大的资源开销。锁的获取、释放以及维护锁的状态都需要消耗系统资源。随着线程数量的增加,这种开销会愈发明显,成为系统性能提升的瓶颈 。

为了解决这些问题,无锁编程应运而生,开启了并发编程的新篇章。它就像是一场创新的集市改革,不再依赖钥匙(锁)来分配摊位,而是通过一种更巧妙的方式,让商人们能够更高效地使用摊位资源。无锁编程摒弃了传统的锁机制,采用原子操作、CAS(Compare-And-Swap)算法等技术,实现了多线程对共享资源的无阻塞访问,让线程在访问共享资源时无需等待锁的释放,大大提高了并发性能 。

二、无锁编程的底层原理剖析

无锁编程具体使用和考虑到的技术方法包括:原子操作(atomic operations), 内存栅栏(memory barriers), 内存顺序冲突(memory order), 指令序列一致性(sequential consistency)和顺ABA现象等等。

在这其中最基础最重要的是操作的原子性或说原子操作。原子操作可以理解为在执行完毕之前不会被任何其它任务或事件中断的一系列操作。原子操作是非阻塞编程最核心基本的部分,没有原子操作的话,操作会因为中断异常等各种原因引起数据状态的不一致从而影响到程序的正确。

2.1原子操作:无锁的基石

原子操作是无锁编程的基石,它确保了指令执行的不可分割性 。就像在建造高楼时,每一块基石都必须坚实稳固,原子操作对于无锁编程也是如此,是构建整个体系的基础。在现代处理器中,简单类型的对齐读写操作通常是原子的,这意味着这些操作要么完全执行,要么完全不执行,不会出现部分执行的情况 。比如对一个int类型变量的赋值操作int a = 10;,在多线程环境下,这个赋值操作要么成功完成,将10赋值给a,要么就没有执行,不会出现只赋了一半值的情况。

而 Read-Modify-Write 操作则更进一步,允许进行更复杂的原子事务性操作 。以经典的i++操作为例,它实际上包含了读取i的值、对值进行加 1 修改、再将修改后的值写回这三个步骤。在传统的非原子操作中,这三个步骤可能会被线程调度打断,导致数据不一致 。但在无锁编程中,通过原子的 Read-Modify-Write 操作,这三个步骤被视为一个整体,不可分割,从而保证了操作的原子性和数据的一致性 。

假设线程 A 和线程 B 都要对共享变量i执行i++操作,如果没有原子操作的保证,可能会出现线程 A 读取i的值后,还没来得及写回,线程 B 就读取了相同的值,最终导致i只增加了 1,而不是 2。但有了原子操作,就能确保两个线程的i++操作都能正确执行,i最终会增加 2 。

2.2CAS 算法:核心机制解析

CAS(Compare-And-Swap)算法是无锁编程的核心机制,它如同无锁编程的 “大脑”,指挥着各个线程有序地访问共享资源 。CAS 算法包含三个参数:V(要更新的变量)、E(预期值)、N(新值) 。其工作原理是:当且仅当变量 V 的值等于预期值 E 时,才会将变量 V 的值更新为新值 N;如果 V 的值和 E 的值不同,那就说明已经有其他线程对 V 进行了更新,当前线程则什么都不做,最后 CAS 返回当前 V 的真实值 。

在一个多线程的计数器场景中,假设有多个线程都要对计数器count进行加 1 操作 。每个线程在执行加 1 操作时,会先读取count的当前值作为预期值 E,然后计算新值 N(即 E + 1),接着使用 CAS 算法尝试将count的值更新为 N 。如果此时count的值仍然等于预期值 E,说明在读取和尝试更新的过程中没有其他线程修改过count,那么更新操作就会成功;反之,如果count的值已经被其他线程修改,不等于预期值 E,更新操作就会失败,线程会重新读取count的当前值,再次尝试 。通过这种不断比较和交换的方式,CAS 算法实现了无锁同步,避免了传统锁机制带来的线程阻塞和性能开销 。

2.3内存屏障与顺序一致性

在多线程环境中,由于处理器的优化和指令重排序等原因,可能会导致内存操作的顺序与程序代码中编写的顺序不一致,从而引发数据一致性问题 。内存屏障就像是一个 “交通警察”,负责维护内存操作的顺序,确保不同线程对内存操作的顺序可见性 。内存屏障通过阻止处理器对其前后的内存操作进行重排序,使得在内存屏障之前的操作一定先于屏障之后的操作完成,从而维持了程序的顺序一致性 。

在一个简单的多线程赋值和读取场景中,线程 A 先对共享变量x进行赋值操作x = 10;,然后对另一个共享变量y进行赋值操作y = 20;;线程 B 则先读取y的值,再读取x的值 。如果没有内存屏障的保证,由于指令重排序,线程 A 的x = 10;和y = 20;操作可能会被重新排序,导致线程 B 读取到的y的值是 20,但读取到的x的值却还是初始值 0,这就破坏了程序的顺序一致性 。但通过在适当的位置插入内存屏障,就可以保证线程 A 的赋值操作按照代码顺序执行,线程 B 读取到的x和y的值也是符合预期的,从而确保了程序的正确性 。

三、无锁队列

无锁队列是lock-free中最基本的数据结构,一般应用场景是资源分配,比如TimerId的分配,WorkerId的分配,上电内存初始块数的申请等等。对于多线程用户来说,无锁队列的入队和出队操作是线程安全的,不用再加锁控制。

3.1无锁队列API

ErrCode initQueue(void** queue, U32 unitSize, U32 maxUnitNum);
ErrCode enQueue(void* queue, void* unit);
ErrCode deQueue(void* queue, void* unit);
U32 getQueueSize(void* queue);
BOOL isQueueEmpty(void* queue);

  • initQueue初始化队列:根据unitSize和maxUnitNum申请内存,并对内存进行初始化。

  • enQueue入队:从队尾增加元素

  • dequeue出队:从队头删除元素

  • getQueueSize获取队列大小:返回队列中的元素数

  • isQueueEmpty队列是否为空:true表示队列为空,false表示队列非空

一文搞懂高效并发编程:无锁编程的秘密与实战

 

相关文章:

高效并发编程:无锁编程

无锁编程是一种并发编程的技术&#xff0c;旨在避免使用传统的锁机制来保护共享数据。相比有锁编程&#xff0c;无锁编程可以提供更高的并发性能和可伸缩性。在无锁编程中&#xff0c;线程或进程通过使用原子操作、CAS&#xff08;Compare-and-Swap&#xff09;等技术来实现对共…...

Java与C语言核心差异:从指针到内存管理的全面剖析

&#x1f381;个人主页&#xff1a;User_芊芊君子 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 &#x1f50d;系列专栏&#xff1a;AI 【前言】 在计算机编程领域&#xff0c;Java和C语言都是极具影响力的编程语言。Java以其跨平台性、安全性和面向对象…...

亚远景-基于ASPICE标准的汽车软件过程优化路径

基于ASPICE标准的汽车软件过程优化路径可以从以下几个方面展开&#xff1a; 1. 评估现状与设定目标 评估现状 &#xff1a;企业需要对当前的软件开发过程进行全面评估&#xff0c;识别与ASPICE标准之间的差距&#xff0c;明确薄弱环节。 设定目标 &#xff1a;根据评估结果和…...

集结号海螺捕鱼游戏源码解析(第三篇):拉霸机模块开发详解与服务器开奖机制

本篇聚焦“拉霸机”子游戏模块&#xff0c;全面剖析客户端滚轮动画机制、服务端中奖算法、中奖广播同步与配置解析方式&#xff0c;适用于技术团队针对拉霸玩法的二次开发与稳定性优化。 一、模块目录结构说明 拉霸机模块的源码目录一般如下&#xff1a; 子游戏/slot_machine…...

图聚类中的亲和力传播

图中展示的是Affinity Propagation&#xff08;亲和力传播&#xff09;算法中的一个关键步骤——更新吸引度矩阵。Affinity Propagation是一种聚类算法&#xff0c;它通过消息传递的方式找到数据集中的代表性样本&#xff08;称为exemplar或原型&#xff09;&#xff0c;并将其…...

Apache中间件解析漏洞与安全加固

Apache作为全球使用最广泛的Web服务器&#xff0c;其灵活性和模块化设计使其成为开发者的首选。然而&#xff0c;其解析机制和配置不当可能导致严重的安全风险。本文将从​​漏洞原理​​、​​攻击案例​​和​​安全配置​​三个维度&#xff0c;结合真实场景&#xff0c;解析…...

MyBatis-Plus分页插件的使用

从MyBatis-Plus 3.4.0开始&#xff0c;不再使用旧版本的PaginationInterceptor &#xff0c;而是使用MybatisPlusInterceptor。 下面是MyBatis-Plus 3.4.3.3新版分页的使用方法。 配置 使用分页插件需要配置MybatisPlusInterceptor&#xff0c;将分页拦截器添加进来&#xff…...

集结号海螺捕鱼游戏源码解析(第二篇):水浒传捕鱼模块逻辑与服务器帧同步详解

本篇将全面解构“水浒传”子游戏的服务端核心逻辑、帧同步机制、鱼群刷新规则、客户端命中表现与服务器计算之间的协同方式&#xff0c;聚焦于 C 与 Unity3D 跨端同步的真实实现过程。 一、水浒传捕鱼模块资源结构 该模块包含三部分核心目录&#xff1a; 子游戏/game_shuihuz…...

开发体育直播系统后台权限设计实践分享|ThinkPHP 技术栈落地案例

今天我们分享的是一套由 东莞梦幻网络科技 自研的体育直播源码&#xff0c;在 ThinkPHP MySQL 技术栈的加持下&#xff0c;后台权限系统如何从0到1落地&#xff0c;并支撑整个平台稳定运行。 一、整体架构设计 用户端&#xff08;APP / H5 / PC&#xff09;↓ 前端接口层&am…...

onlyoffice历史版本功能实现,版本恢复功能,编辑器功能实现 springboot+vue2

文章目录 oonlyoffice历史版本功能实现 &#xff08;编辑器功能实现&#xff09;springbootvue2前提 需要注意把这个 (改成自己服务器的ip或者域名) 改成 自己服务器的域名或者地址1. onloyoffice 服务器部署 搜索其他文章2. 前段代码 vue 22.1 需要注意把这个 (改成自己服务器…...

【漫话机器学习系列】219.支持向量机分类器(Support Vector Classifier)

图解支持向量机分类器&#xff08;Support Vector Classifier&#xff09; 在机器学习的分类模型中&#xff0c;支持向量机&#xff08;Support Vector Machine&#xff0c;SVM&#xff09;是一种功能强大且广泛应用的监督学习算法。它尤其擅长解决小样本、高维度的数据问题&a…...

深入解析 Spring Boot Test:架构、核心组件与最佳实践

深入解析 Spring Boot Test&#xff1a;架构、核心组件与最佳实践 在现代软件开发中&#xff0c;测试是确保应用程序质量的关键环节。Spring Boot Test作为Spring Boot框架的一部分&#xff0c;提供了一套强大且灵活的测试工具&#xff0c;帮助开发者高效地测试Spring Boot应用…...

Sklearn 与 TensorFlow 机器学习实用指南-第八章 降维-笔记

补充&#xff1a; 本文是关于《Sklearn 与 TensorFlow 机器学习实用指南》的学习笔记&#xff0c;基于八、降维 - 【布客】Sklearn 与 TensorFlow 机器学习实用指南 第二版&#xff0c;感谢译者 本文和原文的区别&#xff1a; 本文会更精简、系统地表述书中概念&#xff0c;…...

动态贴纸+美颜SDK的融合实现:底层架构与性能优化技术全解析

如今&#xff0c;美颜动态贴纸功能已经成为提升用户粘性与平台竞争力的“标配”。但从技术实现角度看&#xff0c;如何高效融合动态贴纸与美颜SDK&#xff0c;并在保证画质与流畅度的前提下实现稳定输出&#xff0c;仍然是一项复杂且极具挑战的工程。 本文将深入解析“动态贴纸…...

Git简介与入门

Git的发明 Git由著名的Linux创始人linus于2005年发明&#xff08;所以git的界面、使用方式与Linux挺像的&#xff0c;即命令行方式&#xff09; 经过发展&#xff0c;现在广泛应用于代码管理与团队协作。 Git特性 Git是分布式版本控制系统 分布式 每个开发者拥有完整仓库&…...

车载信息安全架构 --- 汽车网络安全

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 周末洗了一个澡,换了一身衣服,出了门却不知道去哪儿,不知道去找谁,漫无目的走着,大概这就是成年人最深的孤独吧! 旧人不知我近况,新人不知我过…...

Elasticsearch 堆内存使用情况和 JVM 垃圾回收

作者&#xff1a;来自 Elastic Kofi Bartlett 探索 Elasticsearch 堆内存使用情况和 JVM 垃圾回收&#xff0c;包括最佳实践以及在堆内存使用过高或 JVM 性能不佳时的解决方法。 堆内存大小是分配给 Elasticsearch 节点中 Java 虚拟机的 RAM 数量。 从 7.11 版本开始&#xff…...

基于UDP协议的群聊服务器开发(C/C++)

目录 服务器 一、通信 打开网络文件 绑定IP地址与端口号 接收信息 二、数据处理 客户端 三、端口绑定 四、收发信息 五、源码 服务器 在服务器架构设计中&#xff0c;模块解耦是保障系统可维护性的核心准则。本方案采用分层架构将核心功能拆解为通信层与业务处理层两…...

通过自定义序列化来格式化BigDecimal带千分符的字符串

首先&#xff0c;你需要创建一个自定义的 JsonSerializer 来格式化 BigDecimal 为带千分符的字符串。 public class BigDecimalWithCommaSerializer extends JsonSerializer<BigDecimal> {Overridepublic void serialize(BigDecimal value, JsonGenerator gen, Serialize…...

VulnHub-DarkHole_2靶机渗透教程

1.靶机部署 [Onepanda] Mik1ysomething 靶机下载&#xff1a;https://download.vulnhub.com/darkhole/darkhole_2.zip 直接使用VMware导入打开就行 注意&#xff1a;靶机的网络连接模式必须和kali一样&#xff0c;让靶机跟kali处于同一网段&#xff0c;这样kali才能扫出靶机…...

cf | Common Multiple

题目&#xff1a; 代码&#xff1a; 无注释版&#xff1a; #include<bits/stdc.h> using namespace std; #define int long long signed main(){int t;cin>>t;while(t--){int n;cin>>n;map<int,int> mp;mp.clear();for(int i1;i<n;i){int x;cin…...

leetcode hot100尝试1

目录 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案&#xff0c;并且你不能使用两次相同的元素。 你可以按任意顺序返回答案。 c m…...

大模型Agent

一 大模型Agent是什么 &#xff08;一&#xff09;大模型Agent是指基于大语言模型的&#xff0c;能使用工具与外部世界进行交互的计算机程序 感知&#xff08;Perception&#xff09;&#xff1a; ● 家庭助理通过摄像头、麦克风、传感器等设备获取家庭成员的活动信息和环境状…...

阻塞队列的介绍和简单实现——多线程编程简单案例[多线程编程篇(4)]

目录 前言 阻塞队列 阻塞队列相比普通队列的优势 1.天然线程安全 2.实现生产者-消费者模型更加简单 3.自动等待与唤醒 生产者-消费者模型 JAVA标准库中的阻塞队列 阻塞队列的简单实现 前言 在现代软件开发中&#xff0c;多线程编程能力已经成为程序员必须掌握的一项核心…...

服务器配置环境-condapytorch_20250422

文章目录 前言一、conda环境1.1 创建固定python版本的conda环境1.2 激活 Conda 环境1.3 关闭 Conda 环境 二、版本查看CUDA版本当电脑里有多个CUDN时 对照表下载 资源 前言 一、conda环境 1.1 创建固定python版本的conda环境 conda create --name tang_py_3.12 python3.12.41…...

Android Gradle Plugin (AGP) 和 Gradle 的關係

Android Gradle Plugin (AGP) 与 Gradle 的核心关系解析 一、功能定位 Gradle 的通用性‌ Gradle 是跨平台构建工具&#xff0c;支持 Java、Kotlin、C 等多种语言&#xff0c;提供任务自动化、依赖管理等功能。 通过 build.gradle 文件定义构建脚本&#xff0c;管理编译、测试…...

字典树(前缀树)的实现(5)0423

字典树又称前缀树或Trie树&#xff0c;是处理字符串中常见的数据结构。假设组成所有单词的字符仅是"a"~"z"&#xff0c;请实现字典树结构&#xff0c;并包含以下四个功能。 void insert(String word) :添加word&#xff0c;可重复添加。 void delete(Str…...

PHP 反序列化原生类 TIPS字符串逃逸CVE 绕过漏洞属性类型特征

#PHP- 属性类型 - 共有 & 私有 & 保护 1 、对象变量属性&#xff1a; public( 公共的 ): 在本类内部、外部类、子类都可以访问 protect( 受保护的 ): 只有本类或子类或父类中可以访问 private( 私人的 ): 只有本类内部可以使用 2 、序列化数据显示&#xff1a; p…...

专题二十:路由策略与策略路由

一、路由策略 1.1 路由策略的概念 路由策略是通过修改路由表的路由条目来控制数据流量的可达性。即对接受和发布的路由进过滤。这种方式称为路由策略 路由策略功能相关作用控制路由的发布可通过路由策略对所要发布的路由信息进行过滤&#xff0c;只允许发布满足条件的路由信…...

Git 远程操作全攻略:从基础到实战

&#x1f308; 个人主页&#xff1a;Zfox_ &#x1f525; 系列专栏&#xff1a;Git 企业级应用 目录 一&#xff1a;&#x1f525; 理解分布式版本控制系统 二&#xff1a;&#x1f525; 远程仓库 &#x1f98b; 新建远程仓库&#x1f98b; 克隆远程仓库&#x1f98b; 向远程仓…...

VUE自动定义控件SwitchButton

<switch-button style"margin-left: 20rpx;" :buttons["一键打分", "快捷打分"] select"快捷打分" ButtonClick"SwitchButnClick"></switch-button> SwitchButton.vue <template><view class"Di…...

【数据可视化-24】巧克力销售数据的多维度可视化分析

&#x1f9d1; 博主简介&#xff1a;曾任某智慧城市类企业算法总监&#xff0c;目前在美国市场的物流公司从事高级算法工程师一职&#xff0c;深耕人工智能领域&#xff0c;精通python数据挖掘、可视化、机器学习等&#xff0c;发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…...

STM32---串口通信USART

目录 一、串口通信协议 二、USART模块介绍 &#xff08;1&#xff09;移位寄存器 &#xff08;2&#xff09;控制电路 &#xff08;3&#xff09;波特率 &#xff08;4&#xff09;C语言接口 三、串口的引脚初始化 &#xff08;1&#xff09;引脚分布表 &…...

YOLO11改进-Backbone-引入TransXNet替换YOLO backbone 学习全局和局部动态信息,提高检测精度

Vision Transformer 的缺陷&#xff1a;Vision Transformer&#xff08;ViT&#xff09;运用多头自注意力机制在计算机视觉领域取得进展&#xff0c;但它缺乏卷积神经网络&#xff08;CNNs&#xff09;所具有的归纳偏差&#xff0c;导致泛化能力相对较弱。像 Swin Transformer …...

SQL 多表查询:数据整合与分析的强大工具

SQL 多表查询&#xff1a;数据整合与分析的强大工具 在关系型数据库中&#xff0c;数据通常被组织在多个表中。这种表的分离有助于减少冗余并提高数据的管理效率。然而&#xff0c;在实际应用中&#xff0c;往往需要对多个表中的数据进行整合查询&#xff0c;来获得更完整的信…...

MCU开发学习记录11 - ADC学习与实践(HAL库) - 单通道ADC采集、多通道ADC采集、定时器触发连续ADC采集 - STM32CubeMX

名词解释&#xff1a; ADC&#xff1a; Analog-to-Digital SAR&#xff1a;Successive Approximation Register 本文将介绍ADC的概念、相关函数以及STM32CubeMX生成ADC的配置函数。针对于ADC实践&#xff1a;单通道采集芯片内部温度传感器&#xff08;ADC1_ch16&#xff09;&a…...

MacOS中安装Python(homebrew,pyenv)

前言 由于MacOS中自带Python&#xff0c;而自带的Python关联到许多系统组件&#xff0c;不推荐 禁止使用自带Python 安装homebrew包管理器 homebrew官网 打开终端&#xff08;terminal&#xff09;输入以下命令 /bin/bash -c "$(curl -fsSL https://raw.githubusercon…...

从物理到预测:数据驱动的深度学习的结构化探索及AI推理

在当今科学探索的时代&#xff0c;理解的前沿不再仅仅存在于我们书写的方程式中&#xff0c;也存在于我们收集的数据和构建的模型中。在物理学和机器学习的交汇处&#xff0c;一个快速发展的领域正在兴起&#xff0c;它不仅观察宇宙&#xff0c;更是在学习宇宙。 AI推理 我们…...

新书速览|Hadoop与Spark大数据全景解析(视频教学版)

《Hadoop与Spark大数据全景解析:视频教学版》 01 本书内容 《Hadoop与Spark大数据全景解析:视频教学版》结合作者多年在大数据领域的开发实践经验&#xff0c;采用“理论实战”的形式&#xff0c;以大量实例全面介绍Hadoop和Spark的基础知识及其高级应用。作者将丰富的教学经…...

Linux:42线程控制lesson30

代码1&#xff1a;验证join可以去的线程执行完后的退出码/返回值 #include<iostream> #include<unistd.h> #include<pthread.h> #include<string> using namespace std;void* routine(void* arg){string name static_cast<const char*>(arg);i…...

配置 Apache 的 HTTPS

证书文件 文件名 作用 来源 example.com.key 服务器的私钥&#xff0c;用于加密和解密数据。 本地生成 -----BEGIN PRIVATE KEY----- MIIEowIBAAKCAQEAqp5c... -----END PRIVATE KEY----- example.com.csr Certificate Signing Request 证书签名请求文件&#xff0c;包…...

【Flutter高效开发】GetX指南:一文学会状态管理、路由与依赖注入

GetX是Flutter生态中最受欢迎的轻量级全能框架&#xff0c;以其简洁的API设计和卓越的性能著称。本文将带你全面掌握GetX的核心功能和使用技巧&#xff0c;提升你的Flutter开发效率。 一、GetX框架核心优势 1. 三位一体架构设计 模块功能传统方案对比状态管理响应式状态控制…...

第四节:核心概念高频题-Vue生命周期钩子变化

重命名&#xff1a;beforeDestroy→beforeUnmount&#xff0c;destroyed→unmounted 新增&#xff1a;onServerPrefetch&#xff08;SSR场景&#xff09; Vue 生命周期钩子变化详解&#xff08;Vue2 → Vue3&#xff09; 一、核心钩子重命名与语义优化 销毁阶段语义化升级 • …...

安全邮件系统的Maple实现详解

代码改进版&#xff1a; # # 安全邮件系统实现 - 结合DES和RSA加密 # 功能&#xff1a;实现安全的消息加密、签名和传输 # # -------------------------- # 第一部分&#xff1a;消息准备和加密 # --------------------------# 原始消息内容 message : "This is an atte…...

VTK-8.2.0源码编译(Cmake+VS2022+Qt5.12.12)

参考&#xff1a; 安装VTK 详细图文讲解CMake编译VTK&#xff0c;包含详细的编译环境版本 Visual Studio 2022 配置VTK9.3.0 VTK-8.2.0源码编译和初步使用(CmakeVS2015Qt5.14.2) 文章目录 下载编译编译环境介绍配置CMake信息BUILD_SHARED_LIBS控制生成的库是动态链接库&#xf…...

【playwright】学习--持续汇总

seleniumplaywrightselenium 需要结合其他自动化框架&#xff0c;比如pytest之后才能支持web自动化测试playwright 不需要其他自动化框架selenium库》webdriver》浏览器驱动playwright库》playwright driver》浏览器驱动 目录 安装playwright通过pip安装通过VScode安装 安装pla…...

深度解析算法之模拟

39.替换所有的问号 题目链接 给你一个仅包含小写英文字母和 ? 字符的字符串 s&#xff0c;请你将所有的 ? 转换为若干小写字母&#xff0c;使最终的字符串不包含任何 连续重复 的字符。 注意&#xff1a;你 不能 修改非 ? 字符。 题目测试用例保证 除 ? 字符 之外&#…...

leetcode刷题日记——插入区间

[ 题目描述 ]&#xff1a; [ 思路 ]&#xff1a; intervals 有序&#xff0c;需要将一个新的范围插入&#xff0c;然后进行整合方法一&#xff0c;将新的范围插入原 intervals 区间&#xff0c;然后使用 56 题的合并区间函数直接解决方法二&#xff0c; 找出能够包容 newInte…...

gbase8s存储学习一 rootdbs存储结构以及寻址分析

主要层次自下而上为 最小物理存储单元page &#xff0c;多个page 组成逻辑存储单元extent,多个extent 组成物理存储单元chunk ,而多个chunk组成逻辑存储单元dbspace&#xff0c;多个dbspace 组成一个数据库实例 在数据库初始化阶段会生成一个rootdbs表空间&#xff0c;该表空…...

学习设计模式《五》——工厂方法模式

一、基础概念 工厂方法模式的本质是【延迟到子类来选择实现】&#xff1b; 工厂方法模式的定义&#xff1a;定义一个用于创建对象的接口&#xff0c;让子类决定实例化哪一个类&#xff0c;FactoryMethod使一个类的实例化延迟到其子类 。 工厂方法模式的功能 序号说明0工厂方法模…...