SV学习笔记(七)
文章目录
- 类型转换
- 写在前面
- 动态转换
- 子类句柄赋值于父类句柄
- 父类句柄转换为子类句柄
- 虚方法
- 写在前面
- 非虚函数的调用
- 虚函数的调用
- 虚方法的建议
- 为什么使用虚方法
- 对象拷贝
- 写在前面
- 赋值和拷贝
- 总结
- 回调函数
- 写在前面
- 实例
- 完成回调函数功能需要三步:
- 参数化类
- 写在前面
- 实现一个简化的mailbox
- 参考资料
类型转换
写在前面
- 类型转换可以分为 静态转换和动态转换 。
- 静态转换即需要在转换的表达式前 加上单引号 即可,该方式并不会对转换值做检查。如果发生转换失败,我们也无从得知。
- 动态转换即需要使用 系统函数$cast(tgt, src) 做转换。
- 静态转换和动态转换均需要操作符号或者系统函数介入,统称为 显式转换 。
- 不需要显式操作的转换,我们称之为 隐式转换 。例如赋值语句右侧是4位的矢量,而左侧是5位的矢量,隐式转换会先做位宽扩展(隐式),然后再做赋值。
动态转换
- 当我们使用类的时候, 类句柄的向下转换 ,即从父类句柄转换为子类句柄时, 需要 使用$cast() 函数 进行转换, 否则会出现编译错误,这一步也是编译器的保护措施,防止用户出现错误的赋值。
- 如果将子类句柄赋值给父类句柄时,编译器则认为赋值是合法的,但分别 利用子类句柄和父类句柄调用相同对象的成员时,将可能有不同的表现 。
子类句柄赋值于父类句柄
class Transaction;rand bit[31:0] src;function void display(input string prefix="");$display("%s Transaction: src=%0d", prefix, src);endfunction
endclassclass BadTr extends Transaction;bit bad_crc;function void display(input string prefix="");$display("%s BadTr: bad_crc=%b", prefix, bad_crc);super.display(prefix);endfunction
endclassTransaction tr;
BadTr bad, bad2;
Transaction tr;
BadTr bad;
bad=new() ; //构建BadTr扩展对象
tr=bad; //基类句柄指向扩展对象
$display(tr.src) ; //显示基类对象的变量成员
tr.display() ; //??
- tr.display() ; 调用的是父类的display。
父类句柄转换为子类句柄
tr=new() ; //创建一个父类对象
bad=tr; //ERROR:编译错误,即便使用cast进行转换,虽然解决编译错误,但是返回值为0,bad仍为空句柄。
$display(bad.bad_crc) ; //bad_crc成员不在父类对象中
- 将一个父类句柄赋值给一个子类句柄并不总是非法的。
- 但是SV编译器对这种直接赋值的做法是禁止的,也就是说无论父类句柄是否真正指向了一个子类对象,赋值给子类句柄时,编译(静态)都将出现错误。
- 因此需要$cast(tgt, src) 来实现句柄类型的动态转换。
- $cast(tgt, src) 会检查句柄所指向的对象类型, 而不仅仅检查句柄本身。
- 一旦源对象跟目的句柄是同一类型,或者是目的句柄的扩展类,$cast() 函数执行即会成功, 返回1, 否贝返回0。
bad=new(); //创建Bad Tr子对象
tr=bad; //父类句柄指向子类对象
//动态类型转换, 检查tr的源对象是否是bad 2类型或者其子类
//如果转换失败,将报告错误信息
if(!$cast(bad2, tr))$display("cannot assign tr to bad2");$display(bad2.bad_crc); //bad 2指向的对象包含band_src成员
bad2.display() ; //??
- bad2.display() ; 调用子类的方法。
虚方法
写在前面
class basic_test;int fin;int def = 100;function new() ;$display("basic_test::new") ;endfunctiontask test() ;$display("basic_test::test") ;endtask
endclassclass test_wr extends basic_test;int def = 200;function new() ;super.new() ;$display("test_wr::new") ;endfunctiontask test() ;super.test() ;$display("test_wr::test") ;endtask
endclass
- 类的继承是从 继承成员变量和成员方法 两个方面。
- 从例码中可以看到test_wr类和test_rd类分别继承了basic_test类的成员变量以及成员方法。
- 除了介绍的类的封装和继承,关于类的 多态性(polymorphism) 也是必须关注的。
- 正是由于类的多态性,使得用户在设计和实现类时, 不需要担心句柄指向的对象类型是父类还是子类,只要通过虚方法,就可以实现动态绑定(dynamic binding) , 或者在SV中称之为动态方法查找(dynamic method lookup) 。
非虚函数的调用
basic_test t;
test_wr wr;
initial beginwr=new() ;t=wr;$display("wr test starts") ;wr.test() ;$display("wr test ends") ;$display("t test starts") ;t.test() ;$display("t test ends") ;
end//输出结果:
// wr test starts
// basic_test::test
// test_wr::test
// wr test ends
// t test starts
// basic_test::test
// t test ends
- 首先, 在执行wr.test() 时, 由于wr类型为test_wr, 则索引到的test() 应该为test_wr类的方法test。
- 同时, 由于在test_wr::test中显式调用了super.test() , 则会先执行basic_test::test, 然后再执行test_wr::test中其余的代码。
- 这里值得注意的是, 默认情况下, 子类覆盖(override) 的方法并不会继承父类同名的方法, 而只有通过super.method()的方式显式执行,才会达到继承父类方法的效果,初学SV的用户容易在这里混淆方法覆盖和类继承的概念。
- 当wr对象的句柄传递给t后, 由于t本身是basic_test类, 所以,在执行t.test时, t只会搜寻basic_test::test方法。
- (多态的问题是什么?在句柄传递中,子类句柄赋值给父类句柄,调用同名函数时,子类句柄调用的是子类函数,父类句柄调用的是父类函数,即便把子类句柄赋值给了父类句柄,也无法通过父类句柄调用子类函数)
虚函数的调用
- 我们将已经在编译阶段就可以确定下来调用方法所处作用域的方式称之为静态绑定(static binding) , 而与之相对的是动态绑定。
- 动态绑定指的是,在调用方法时,会 在运行时来确定句柄指向对象的类型,再动态指向应该调用的方法 。
- 为了实现动态绑定, 我们将basic_test::test定义为虚方法。
class basic_test;...virtual task test(stm_ini ini) ;$display("basic_test::test") ;endtask...
endclass//wr test starts只做了这么一个改动以后,我们重复运行之前的测试代码,可以看到运行结果变为:
// wr test starts
// basic_test::test
// test_wr::test
// wr test ends
// t test start.s
// basic_test::test
// test_wr::test
// t test ends
- 由于声明了basic_test::test为虚方法, 系统在执行t.test时,会检查t所指向对象的类型为test_wr类, 进而调用test_wr::test。
- 于是, 输出结果与调用wr.test一致。
- 我们就可以通过虚方法的使用来实现类成员方法调用时的动态查找,用户无需担心使用的是父类句柄还是子类句柄,因为最终都会实现动态方法查找,执行正确的方法。
虚方法的建议
- 在为父类定义方法时,如果该方法 日后可能会被覆盖或者继承 ,那么应该声明为虚方法。
- 虚方法如果要定义,应该 尽量定义在底层父类中 。这是因为如果virtual是声明在类继承关系的中间层类中, 那么只有从该中间类到其子类的调用链中会遵循动态查找,而最底层类到该中间类的方法调用仍然会遵循静态查找。
- 虚方法 通过virtual声明, 只需要声明一次即可 。例如上面代码中,只需要将basic_test::test声明为virtual, 而 其子类则无需再次声明 ,当然再次声明来表明该方法的特性也是可以的。
- 虚方法的继承也需要 遵循相同的参数和返回类型 ,否则,子类定义的方法须归为同名不同参的其它方法。
为什么使用虚方法
- 首先:当 父类指针指向子类对象 ,如果不将test函数声明为虚函数,最终调用的是父类test函数;如果将test函数声明为虚函数,那么调用的是子类test函数。
- 为什么要用父类指针指向子类对象呢?用子类指针指向子类对象不好吗?
虽然这样说,但是实际开发过程中不是这样的,当我们使用一些类库、框架的时候,这些类库、框架是事先就写好的。我们在使用的时候不能直接修改类库的源码,我们只能派生类库中的类来覆盖一些成员函数以实现我们的功能,但这些成员函数有的是由框架调用的。这种情况下,用虚函数是很好的办法。
NND,这不就是C++吗?
对象拷贝
写在前面
- 对于拷贝(copy) , 对象的拷贝要比其它SV的变量类型都让人“当心”。
- 因为就SV普通的变量拷贝而言,只需要通过赋值操作符“=”就足够了。
- 而对象的拷贝则无法通过“=”来实现,因为这一操作是句柄的赋值,而不是对象的拷贝。
test_wr h;
initial beginwr = new();h = wr;$display("wr.def=%Od", wr.def);$display("h.def=%0d", h.def);h.def = 300;$display("wr.def=%Od", wr.def);$display("h.def=%0d", h.def);
end
//输出结果:
// wr.def = 200
// h.def = 200
// wr.def = 300
// h.def = 300
- 在h=wr之后,由于是句柄的赋值,所以h.def=300的操作, 实际上是对这两个句柄指向的共同对象做的成员变量赋值。所以,从最终打印的结果可以看出,wr.def与h.def的值相同。
- 那么如果要拷贝对象,指的是首先创建一个新的对象(开辟新的空间),再将目标对象的成员变量值拷贝给新对象的成员,这就使得新对象与目标对象的成员变量数值保持一致,即完成了对象的拷贝(成员变量的拷贝)。
- 初学者需要区别句柄拷贝与对象拷贝的区别。
软件来说,我们可能称呼的是值拷贝与引用拷贝
class basic_test; //父类...virtual function void copy_data(basic_test t) ;t.def=def;t.fin=fin;endfunctionvirtual function basic_test copy() ;basic_test t=new(0) ; //创建父类对象copy_data(t) ;return t;endfunction
endclassclass test_wr extends basic_test; //子类...function void copy_data(basic_test t) ;test_wr h;super.copy_data(t) ;$cast(h, t); //关键代码,句柄转化h.def=def;endfunctionfunction basic_test copy() ;test_wr t=new() ; //创建子类对象copy_data(t) ;return t;endfunction
endclass
module tb;....test_wr wr; //子类test_wr h; //子类initial beginwr=new() ;$cast(h, wr.copy()); //copy会返回父类句柄,所以这里将父类句柄转化为子类句柄$display("wr.def=%0d", wr.def);$display("h.def=%0d", h.def);h.def=300;$display("wr.def=%0d", wr.def);$display("h.def=%0d", h.def);end...
endmodule//输出结果:
// wr.def=200
// h.def=200
// wr.def=200
// h.def=300
赋值和拷贝
声明变量和创建对象是两个过程,也可以一步完成。
Packet pl;
p1=new;
如果将p1赋值给另外一个变量p2,那么依然只有一个对象,只是指向这个对象的句柄有p1和p2.
以下这种方式表示p1和p2代表两个不同的对象。
在创建p2对象时, 将从p 1拷贝其成员变量例如integer、string和句柄等, 该种拷贝方式称为浅拷贝(shallowcopy) 。
Packet pl;
Packet p2;
p1=new;
p2=new p1;
总结
- 将成员拷贝函数copy_data() 和新对象生成函数copy() 分为两个方法,这样使得子类继承和方法复用较为容易。
- 为了保证父类和子类的成员均可以完成拷贝,将拷贝方法声明为虚方法,且遵循只拷贝该类的域成员的原则,父类的成员拷贝应由父类的拷贝方法完成。
- 在实现copy_data() 过程中应该注意句柄的类型转换, 保证转换后的句柄可以访问类成员变量。
回调函数
写在前面
- 理想的验证环境是在被移植做水平复用或者垂直复用时,应当尽可能少地修改模块验证环境本身,只在外部做少量的配置,或者定制化修改就可以嵌入到新的环境中。
- 要做到这一点,一方面我们可以通过顶层环境的配置对象自顶向下进行配置参数传递,另外一方面我们可以在测试程序不修改原始类的情况下注入新的代码。
- 例如, 当我们需要修改stimulator的行为时, 有两种选择, 一个是修改父类,但针对父类的会传播到其它子类;另外一个选择是,在父类定义方法时,预留回调函数入口,使得在继承的子类中填充回调函数,就可以完成对父类方法的修改。
实例
- 示意:
virtual class Driver_cbs; //Driver回调虚类virtual task pre_tx(ref Transaction tr, ref bit drop) ;//默认不做操作endtaskvirtual task post_tx(ref Transaction tr) ;//默认不做操作endtask
endclass
- 实例:
class Driver;Driver_ebs cbs[$];task run() ;bit drop;Transaction tr;forever begindrop=0;agt2drv.get(tr) ;foreach(ebs[il) cbs[il.pre_tx(tr, drop) ;if(drop) continue;transmit(tr) ;foreach(cbs[il) cbs[i] .post_tx(tr) ;endendtask
endclassclass Driver_cbs_drop extends Driver_abs;virtual task pre_tx(ref Transaction tr, ref bit drop) ;//1/100的传输事务丢弃概率drop=($urandom range(0, 99) ==0) ;endtask
endclassprogram automatic test;Environment env;initial beginenv=new() ;env.gen_cfg() ;env.build() ;begin//创建回调对象井且植入driverDriver_abs_drop dcd=new() ;env.drv.cbs.push_back(dcd) ;endenv.run() ;env.wrap_up();end
endprogram
完成回调函数功能需要三步:
- 预留回调函数入口
- 定义回调的类和回调函数
- 例化和添加回调的类
参数化类
写在前面
- 参数化的使用是为了提高代码的复用率。
- 无论是设计还是验证,如果代码会被更多的人使用或者被更多的项目所采用,那么就需要考虑使用参数来提高复用率。
- 参数的使用越合理,后期维护的成本就会相应降低。
- 在硬件设计中,参数往往是整型,例如端口数目或者位宽。在验证环境中,参数的使用更加灵活,可以使用各种类型来做类定义时的参数。
- 在SV中,可以为类增加若干个数据类型参数,并在声明类句柄的时候指定类型。
- SV的类参数化近似于C++中的模板。
实现一个简化的mailbox
class mailbox;local int queue[$] ;task put(input int i) ;queue.push_back(i) ;endtasktask get(ref int o) ;wait(queue.size() >0) ;o=queue·pop_front() ;endtasktask peek(ref int o) ;wait(queue.size() >0) ;o=queue[0] ;endtask
endclass
- 这个简化的mailbox的问题在于它只能用于操作整数类型。
- 如果要存储real类型, 或者某一个类的句柄,那么就得复制该类,然后将数据类型由int类型转换为real类型或者某一个类的类型。
- 这样将导致类的快速增长,而且是重复代码的大规模增长,代码维护将变得冗长乏味而且还容易出错。
class mailbox #(type T=int) ;local T queue[$] ;task put(input T i) ;queue.push_back(i) ;endtasktask get(ref T o) ;wait(queue.size() >0) ;o=queue.pop_front() ;endtasktask peek(ref T o) ;wait(queue.size() >0) ;o=queue[Ol;endtask
endclassinitial beginreal o;mailbox #(real) mb; //创建一个存储real类型的mailboxmb=new() ;for(inti=0; i<5; i++)mb.put(i*2.0) ; //将real值存储入mbfor(inti=0; i<5; i++)mb.get(o) ; //从mb取出real值
end
- 在类定义时添加参数#(typeT=int) , 这表示后期类在声明变量时如果不指定参数类型, 则默认采用int类型。
- 将原代码int用参数T来代替。
- 参数化的类将可以在后期例化时使用不同的参数,以此来存储不同的数据类型。
参考资料
- Wenhui’s Rotten Pen
- SystemVerilog
- chipverify
相关文章:

SV学习笔记(七)
文章目录 类型转换写在前面动态转换子类句柄赋值于父类句柄父类句柄转换为子类句柄 虚方法写在前面非虚函数的调用虚函数的调用虚方法的建议为什么使用虚方法 对象拷贝写在前面赋值和拷贝总结 回调函数写在前面实例完成回调函数功能需要三步: 参数化类写在前面实现一…...
Windows SDK(五)按钮静态文本与编辑框控件
我们首先应该知道,所谓按钮静态文本等等控件都是窗口,他们都是隶属于父窗口下的子窗口,所 以在创建控件前,我们要首先创建一个父窗口,此处我们直接使用Windows桌面程序创建时,程 序自动为我们创建的一个窗…...

基于SSM框架实现的在线心理评测与咨询系统(技术栈 spring+springmvc+mybatis+jsp+jquery+css)
一、项目简介 本项目是一套基于SSM框架实现的在线心理评测与咨询系统,主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含:项目源码、数据库脚本等,该项目附带全部源码可作为毕设使用。 项目都经过严格调试&am…...

GD32F470_ DS18B20温度传感器模块移植
DS18B20温度传感器 DS18B20数字温度传感器提供9位至12位精度的温度测量,并具有非易失性用户可编程上下触发点报警功能。DS18B20通过单总线通信,根据定义,只需要一条数据线(和地线)即可与单片机通信。此外,DS18B20可以直接从数据线…...

【JAVASE】带你了解instanceof和equals的魅力
✅作者简介:大家好,我是橘橙黄又青,一个想要与大家共同进步的男人😉😉 🍎个人主页:再无B~U~G-CSDN博客 1.instanceof instanceof 是 Java 的保留关键字。它的作用是测试…...

【Linux】进程控制详解
目录 前言 进程创建 认识fork 写时拷贝 再谈fork 进程终止 进程退出码 用代码来终止进程 常见的进程终止的方式 exit _exit 进程等待 进程等待的必要性 进程等待的方式 wait waitpid 详解status参数 详解option参数 前言 本文适合有一点基础的人看的&#…...
Mysql 高性能的sql优化方案和建议
优化MySQL的性能是一项复杂而关键的任务,它可以通过多种方式来实现。下面是一些SQL优化的方案和建议: 索引优化: 确保经常查询的列都有索引。但不要过度索引,因为它可能会增加写入操作的开销。使用组合索引来覆盖多个查询条件。…...

鸿蒙实战开发:【实现应用悬浮窗】
如果你要做的是系统级别的悬浮窗,就需要判断是否具备悬浮窗权限。然而这又不是一个标准的动态权限,你需要兼容各种奇葩机型的悬浮窗权限判断。 fun checkPermission(context: Context): Boolean if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)…...
应用开发:python解析斗鱼弹幕
解决问题 互动弹幕,关注提问 ,ai回答 技术 python playwright 调用接口 https://github.com/broven/DouYudanmu/blob/master/douyu.py 演示 放弃 这个根本不是研究方向 定位错误 你浪费下午时间,定位错误 这个跟本不是你的方向。 4个小时看斗…...

【面试经典150 | 动态规划】交错字符串
文章目录 写在前面Tag题目来源解题思路方法一:动态规划 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法,两到三天更新一篇文章,欢迎催更…… 专栏内容以分析题目为主,并附带一些对于本题涉及到的数据结构等内容进行…...
设计模式(17):中介者模式
核心: 如果一个系统中对象之间的联系呈现网状结构,对象之间存在大量多对多关系,导致关系及其复杂,这些对象称为“同事对象”。我们可以引入一个中介者对象,使各个同事对象只跟中介者对象打交道,将复杂的网…...

echart 折线图或散点图当横坐标为小数位时,若想显示整数该如何处理?
如图当前是这样的: 横坐标刻度目前是小数位,如果直接将小数位取整则会失去精度,所以我们要做的是刻度即是整数,又能显示小数位对应的数值; 思路就是直接手动设置刻度:设置xAxis的min,max,splitNumber,同时不…...

一套C#自主版权+应用案例的手麻系统源码
手术麻醉信息管理系统源码,自主版权应用案例的手麻系统源码 手术麻醉信息管理系统包含了患者从预约申请手术到术前、术中、术后的流程控制。手术麻醉信息管理系统主要是由监护设备数据采集子系统和麻醉临床系统两个子部分组成。包括从手术申请到手术分配,…...

31.2k star, 免费开源的白板绘图工具 tldraw
31.2k star, 免费开源的白板绘图工具 tldraw 分类 开源分享 项目名: tldraw -- 无限画布白板 Github 开源地址: https://github.com/tldraw/tldraw 在线测试地址: tldraw 文档地址: tldraw SDK tldraw 是一款开源免费的无限画布白板&…...

Redis开源协议调整,我们怎么办?
2024年3月20日, Redis官方宣布,从 Redis 7.4版本开始,Redis将获得源可用许可证 ( RSALv2 ) 和服务器端公共许可证 ( SSPLv1 ) 的双重许可,时间点恰逢刚刚完成最新一轮融资,宣布的时机耐人寻味。 Redis协议调整,对云计算…...
干了三年外包。。。忘了什么是CICD。。。
干了三年外包。。。忘了什么是CICD。。。 CI/CD(持续集成与持续交付) 是一种软件开发实践,它可以帮助我们更快地交付高质量的软件产品。CI/CD的核心思想是将软件开发过程中的各个阶段自动化,从而减少人工干预,提高开发效率和产品质量。本文将…...
【LeetCode】454. 四数相加 II
目录 题目 思路 代码 题目 题目链接:. - 力扣(LeetCode) 给你四个整数数组 nums1、nums2、nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足: 0 < i, j, k, l < nnums1…...
搜索(DFS BFS)
DFS 常规DFS: 二叉树前序,中序,后序遍历-CSDN博客 void postorderTraversal(root)初始化一个空列表 arrfind访问总树(root,arr)return arrvoid find(temp, arr)if temp 为空return // 调用顺序由前中后序决定find递归访问左子树find递归访问右子树arr加入当前节点…...
koc和kol是什么意思?
一、koc和kol是什么意思? koc和kol是专业术语。KOC是关键意见消费者的意思,是Key Opinion Consumer的缩写;KOL是关键意见领袖的意思,是Key Opinion Leader的缩写。 1、关键意见领袖kol “关键意见领袖”通俗地讲是达人。这些人…...

基于vscode Arduino插件开发Arduino项目
基于vscode Arduino插件开发arduino项目 插件配置问题记录1. 指定编译输出文件夹2. 编译下载时不输出详细信息3. 输出端口信息乱码4. 通过串口输出中文,vscode对应的串口助手上会显示乱码(未解决) 插件配置 环境:Arduino插件版本…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...

如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序
一、开发环境准备 工具安装: 下载安装DevEco Studio 4.0(支持HarmonyOS 5)配置HarmonyOS SDK 5.0确保Node.js版本≥14 项目初始化: ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...