Qt -信号与槽
博客主页:【夜泉_ly】
本文专栏:【暂无】
欢迎点赞👍收藏⭐关注❤️
目录
- 前言
- 引入
- connect调用链
- 模板类型的connect
- QObject::connectImpl
- QObjectPrivate::connectImpl
- qobject_p_p.h
- connect作用总结
- ai对信号与槽的模拟实现
前言
面向对象,
这个词从开始学 C++ 我们就知道了,
但我们或许仍然不能真正理解它。
而本篇的信号与槽,
或许多多少少能加深我们对面向对象的认识。
引入
信号与槽,
本质解决的是对象之间的通信问题。
很简单的一个例子:
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);QPushButton* btn = new QPushButton(this);btn->setText("关闭窗口");connect(btn, &QPushButton::clicked, this, &QWidget::close); // 针对不同对象。点击按钮,关闭窗口
}
在这里,
connect
将一个按钮和一个控件建立了连接。
点击按钮,
按钮会告诉控件:
你该关闭了。
很明显按钮和控件是两个不同的对象,
而它们能够通信,
借助的就是信号与槽。
connect调用链
模板类型的connect
为了加深理解,
下面我们来简单看看Qt中对刚刚的 connect
的处理。
首先,当我们写下:
connect(btn, &QPushButton::clicked, this, &QWidget::close);
会调用 qobject.h
的模板类型的 connect
(227行左右)
//connect with context
template <typename Func1, typename Func2>
static inline QMetaObject::Connectionconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,const typename QtPrivate::ContextTypeForFunctor<Func2>::ContextType *context, Func2 &&slot,Qt::ConnectionType type = Qt::AutoConnection)
之后会进行一系列的检查,
用了大量 TMP
的知识,
我暂时看不懂。
总之,大概检查了信号和槽的各种类型后,
调用了 connectImpl
,
impl
是 implementation
(实现)的缩写,
所以这里才是连接信号和槽的地方。
(那 connect
的几十行代码全用来检查了?恐怖如斯)
connect
函数末尾:
QObject::connectImpl
这个 connectImpl
也有很多地方实现了,
不过根据参数类型,
我觉得它调的是这个 QObject::connectImpl
:
qobject.cpp
5324行左右
QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signal,const QObject *receiver, void **slot,QtPrivate::QSlotObjectBase *slotObjRaw, Qt::ConnectionType type,const int *types, const QMetaObject *senderMetaObject)
查了查,
Qt 的信号是由 moc 工具生成的元数据,
依赖于 QObject
和 QMetaObject
。
而这个 QObject::connectImpl
的作用就是:
使用 QMetaObject
的元信息查找信号的索引 signal_index
。
然后在函数末尾调用了 QObjectPrivate::connectImpl
:
return QObjectPrivate::connectImpl(sender, signal_index, receiver, slot, slotObj.release(), type, types, senderMetaObject);
QObjectPrivate::connectImpl
qobject.cpp
5370行左右
QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int signal_index,const QObject *receiver, void **slot,QtPrivate::QSlotObjectBase *slotObjRaw, int type,const int *types, const QMetaObject *senderMetaObject)
这下才是真的来到核心实现了🤣。
我觉得最重要的两句话:
std::unique_ptr<QObjectPrivate::Connection> c{new QObjectPrivate::Connection};
QObjectPrivate::get(s)->addConnection(signal_index, c.get());
这里创建了一个 QObjectPrivate::Connection
对象,
在里面保存信号和槽的连接信息。
又用 QObjectPrivate::get(s)
即指向信号发送者( sender
)的 QObjectPrivate
指针,
调用 addConnection()
而 addConnection。。。
qobject_p_p.h
我们还是先看看 QObjectPrivate
中的几个结构体吧:
struct Connection;
struct ConnectionData;
struct ConnectionList;
struct ConnectionOrSignalVector;
struct SignalVector;
struct Sender;
struct TaggedSignalVector;
定义在 qobject_p_p.h
中,
共同构成了 Qt 信号与槽机制的底层实现。
Connection的关键字段(我认为的):
struct QObjectPrivate::Connection : public ConnectionOrSignalVector
{QObject *sender;QAtomicPointer<QObject> receiver;union {StaticMetaCallFunction callFunction;QtPrivate::QSlotObjectBase *slotObj;};signed int signal_index : 27; // In signal range (see QObjectPrivate::signalIndex())ushort connectionType : 2; // 0 == auto, 1 == direct, 2 == queued, 3 == blocking
};
Connection
表示信号与槽之间的一个具体连接,
是个双链表的节点(指针被我省略了,因为我看不懂)。
sender
发出信号的对象receiver
接收信号的对象union
中,提供两种方式去调用函数
且因为是union
,所以同时只存在一个方法
Qt会根据你传的槽去选择:callFunction
对应 成员函数slotObj
对应lambda
表达式、仿函数等复杂点的对象
ConnectionData
的关键字段(我认为的):
struct QObjectPrivate::ConnectionData
{QAtomicPointer<SignalVector> signalVector;Connection *senders = nullptr;Sender *currentSender = nullptr;
};
-
signalVector
存的与对象相关的所有信号的连接信息。
每个元素对应一个ConnecionList
,
存储了与该信号相关的所有槽的连接信息。
-
senders
存的连接到当前对象槽的信号的连接信息。
从类型Connection
看出,这是个双链表。
-
currentSender
指的是当前被激活的信号发送者,
当有信号被激活,会有个Sender
对象被创建,并连接到这里。
具体的细节。。嘶,又要跳文件吗 !?
好像激活和qobjectdefs.h
的QMetaObject::activate
有关,
暂时不看了。
但Sender
的构造可以看看,
这里体现了连接到currentSender
的过程:Sender(QObject *receiver, QObject *sender, int signal, ConnectionData *receiverConnections): receiver(receiver), sender(sender), signal(signal) {if (receiverConnections) {previous = receiverConnections->currentSender;receiverConnections->currentSender = this;} }
connect作用总结
那么看到这里,
似乎 addConnection
不太需要看了,
Qt的 SignalVector
使用了非常规的方法表示数组,
主要利用的是指针的偏移,
所以相关的代码都涉及大量的指针操作,
提高了性能,
但降低了我这种fw的阅读体验。
总结一下 QObjectPrivate::connectImpl
的主要作用吧:
创建连接信息,用的 Connection
结构体。
将连接信息添加到发送者的 signalVector
中
将连接信息添加到接收者的 senders
中
最后回到开头的例子:
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);QPushButton* btn = new QPushButton(this);btn->setText("关闭窗口");connect(btn, &QPushButton::clicked, this, &QWidget::close); // 针对不同对象。点击按钮,关闭窗口
}
发送者就是 btn
,是个按钮。
接收者就是 this
, 是个控件。
通过 connect
:
btn
的 singalVector
的 clicked
信号的 ConnecionList
多了一个 Connection
,
this
的 senders
双链表中 也多了一个 Connection
,
而这两个地方指向的是同一个 Connection
结构体,
而这个 Connection
的内容:
sender
就是 btn,即按钮
receiver
就是 this,即控件
callFunction
就是 QWidget::close
。(因为 QWidget::close
是个成员函数,所以union
中是 callFunction
,而不是 slotObj
)
signal_index
就是 QPushButton::clicked
信号对应的下标。
这就是建立连接的过程了。
至于调用。。力竭了,不想看了。。
ai对信号与槽的模拟实现
最后,看看ai的模拟实现吧:
类型检查虽然非必须,
但 TMP 真的帅啊。。。
#include <iostream>
#include <vector>
#include <functional>
#include <tuple>// 检查每一对参数类型是否兼容的类型特征
template <typename SignalArgsTuple, typename SlotArgsTuple>
struct CheckCompatibleArguments;// 基本情况:参数列表为空
template <>
struct CheckCompatibleArguments<std::tuple<>, std::tuple<>> {static constexpr bool value = true;
};// 递归情况:逐一检查所有参数对
template <typename SignalArg, typename... SignalRest,typename SlotArg, typename... SlotRest>
struct CheckCompatibleArguments<std::tuple<SignalArg, SignalRest...>, std::tuple<SlotArg, SlotRest...>
> {static constexpr bool value =std::is_convertible<SignalArg, SlotArg>::value&&CheckCompatibleArguments<std::tuple<SignalRest...>, std::tuple<SlotRest...>>::value;
};// Signal类定义,用于表示信号,管理连接的槽
template <typename... Args>
class Signal {std::vector<std::function<void(Args...)>> slots;public:// 连接槽函数到当前信号template <typename F>void connect(F&& f) {slots.emplace_back(std::forward<F>(f));}// 触发信号,传播参数至所有已连接的槽void emit(Args... args) {for (auto& slot : slots) {slot(args...);}}
};// 全局connect函数,用于连接信号和成员函数槽
template <typename Receiver, typename... SignalArgs, typename... SlotArgs>
void connect(Signal<SignalArgs...>& signal,Receiver* receiver,void (Receiver::* slot)(SlotArgs...)
) {// 确保信号和槽参数个数匹配static_assert(sizeof...(SignalArgs) == sizeof...(SlotArgs),"Signal and slot have different number of arguments");// 确保参数类型兼容static_assert(CheckCompatibleArguments<std::tuple<SignalArgs...>,std::tuple<SlotArgs...>>::value,"Signal and slot arguments are not compatible");signal.connect([receiver, slot](SignalArgs... args) {(receiver->*slot)(args...);});
}// 示例发送者类:按钮
class Button {
public:Signal<int> clicked; // 带整数参数(点击次数)的信号void press() {static int count = 0;clicked.emit(++count); // 发出信号}
};// 示例接收者类:标签
class Label {
public:void showCount(int num) {std::cout << "点击次数:" << num << std::endl;}
};int main() {// 测试 1: 基本测试:按钮点击信号和标签的显示槽连接Button button;Label label;// 连接按钮的点击信号到标签的显示槽connect(button.clicked, &label, &Label::showCount);// 模拟用户点击按钮button.press(); // 输出:点击次数:1button.press(); // 输出:点击次数:2std::cout << "-------------------" << std::endl;// 测试 2: 多个槽连接到同一个信号Button button2;Label label2;Label label3;// 连接按钮的点击信号到多个槽connect(button2.clicked, &label2, &Label::showCount);connect(button2.clicked, &label3, &Label::showCount);// 模拟用户点击按钮button2.press(); // 输出:点击次数:1button2.press(); // 输出:点击次数:2std::cout << "-------------------" << std::endl;// 测试 3: 使用不同类型的信号和槽class StringLabel {public:void showString(const std::string& str) {std::cout << "显示字符串:" << str << std::endl;}};Signal<std::string> stringSignal;StringLabel stringLabel;// 连接信号和槽connect(stringSignal, &stringLabel, &StringLabel::showString);// 发射一个字符串信号stringSignal.emit("Hello, world!"); // 输出:显示字符串:Hello, world!std::cout << "-------------------" << std::endl;// 测试 4: 测试无参信号Signal<> noArgSignal;class NoArgLabel {public:void notify() {std::cout << "信号发射了!" << std::endl;}};NoArgLabel noArgLabel;// 连接无参信号和槽connect(noArgSignal, &noArgLabel, &NoArgLabel::notify);// 发射无参信号noArgSignal.emit(); // 输出:信号发射了!std::cout << "-------------------" << std::endl;// 测试 5: 参数类型不兼容的错误(编译时错误)// Uncommenting the code below will result in a compilation error.// Signal<double> doubleSignal;// connect(doubleSignal, &label, &Label::showCount); // 编译错误:类型不兼容return 0;
}
运行结果:
希望本篇文章对你有所帮助!并激发你进一步探索编程的兴趣!
本人仅是个C语言初学者,如果你有任何疑问或建议,欢迎随时留言讨论!让我们一起学习,共同进步!
相关文章:
Qt -信号与槽
博客主页:【夜泉_ly】 本文专栏:【暂无】 欢迎点赞👍收藏⭐关注❤️ 目录 前言引入connect调用链模板类型的connectQObject::connectImplQObjectPrivate::connectImpl qobject_p_p.hconnect作用总结ai对信号与槽的模拟实现 前言 面向对象&am…...
macos 魔搭 模型下载 Wan-AI ComfyUI
环境安装 ➜ ~ sw_vers ProductName: macOS ProductVersion: 15.3.2 ➜ ~ pip --version pip 24.3.1 from /opt/homebrew/lib/python3.11/site-packages/pip (python 3.11)安装ModelScope SDK pip install modelscope➜ ~ modelscope download --help Traceback (most r…...
Xshell Plus 6下载与安装
文章目录 Xshell Plus 6 简介(一)网络连接与协议支持(二)会话管理(三)安全特性(四)文件传输功能(因集成Xftp 6 )(五)个性化与便捷功能…...
Kubernetes 集群搭建(一):从环境准备到 Calico 网络插件部署
(一)虚拟环境准备 名称ip备注m1192.168.101.131mastern1192.168.101.132workern2192.168.101.133worker (二)集群统一配置 2.1 关闭防火墙和selinux systemctl stop firewalld systemctl disable firewalld sed -i s/enforcin…...
【国产突围!致远电子ZXDoc如何打破Vector垄断,成为新能源车研发“神器”?】
摘要:在汽车“新四化”浪潮下,国产汽车总线工具链软件正迎来高光时刻!广州致远电子推出的ZXDoc以全栈自主化技术硬核国产芯片生态,斩获2024金辑奖“最佳技术实践应用奖”,成为新能源车企研发工程师的“效率倍增器”。本…...
3-Visual Studio 2022打包NET开发项目为安装包
引言 本文将上一期博文>>>门店管理系统开发<<<开发的项目打包为Windows安装包 一,安装扩展 安装此扩展:installer Projects 二,创建安装程序项目 创建项目 右键解决方案-添加-新建项目 选择setup Project项目 填写项目名…...
Cookie、Session、Token、JWT的区别和使用场景
Cookie、Session和Token的区别 存储位置数据容量安全性生命周期性能Cookie客户端(通常是浏览器)4KB、Cookie数量也有限制不安全、XSS(跨站脚本攻击)、CSRF(跨站请求伪造)可以设置过期时间,过期后…...
P1883 【模板】三分 | 函数
题目描述 给定 n 个二次函数 f1(x),f2(x),…,fn(x)(均形如 ax2bxc),设 F(x)max{f1(x),f2(x),...,fn(x)},求 F(x) 在区间 [0,1000] 上的最小值。 输入格式 输入第一行为正整数 T,表示有 T 组数据。 每组…...
Ruoyi-vue plus 5.2.2 flowble设计流程点击开始流程图错误
网关设置条件或者是事件删除后出现,点击网关节点无法找到下面的事件节点。 配置页面事件错误,点背景配置进去了事件,发现再次加载,或者删除的时候VUE页面无法加载。 解决方式:查看XML文件,这个节点是否存在…...
MySQL学习笔记(三)——图形化界面工具DataGrip
目录 1. 图形化界面工具 2.下载 3. 安装 3.1 安装步骤 3.2 激活说明 4. 使用 4.1 汉化教程 4.2 使用 1. 图形化界面工具 上述,我们已经讲解了通过 DDL 语句,如何操作数据库、操作表、操作表中的字段,而通过 DDL 语句执行在命令进行操…...
keil软件仿真
设置 选择软件仿真。 修改参数。 获取参数 找到自己的芯片信号。这里用的是F103ZET6 复制下来,并对其进行修改。 接下来进入仿真即可...
每日一题(小白)模拟娱乐篇14
直接理解题意,一分钟扩散一次,那么2020分钟也就是需要循环2020次,然后加入扩散后的条件,每一个次扩散使方格子的总量1(只要有一个点扩散就无需看其他的点),若干次循环过后总数之和即所有黑色格子…...
(二)使用Android Studio开发基于Java+xml的安卓app之环境搭建
以下是使用Android Studio搭建基于Java和XML的Android应用开发环境的详细步骤: 一、系统要求 操作系统:Windows 7/8/10/11(64位)内存:建议8GB及以上磁盘空间:至少5GB空闲(建议预留10GB以上&…...
STM32定时器通道1-4(CH1-CH4)的引脚映射关系
以下是 STM32定时器通道1-4(CH1-CH4)的引脚映射关系的详细说明,以常见型号为例。由于不同系列/型号差异较大,请务必结合具体芯片的参考手册确认。 一、STM32F1系列(如STM32F103C8T6) 1. TIM1(高级定时器) 通道默认引脚重映射引脚(部分/完全)备注CH1PA8无互补输出CH1…...
看爬山虎学本领 软爬机器人来创新 各种场景能适应
*本文只做阅读笔记分享* 一、灵感来源:向植物取经 大家好!今天来聊一款超酷的软爬机器人,它的灵感来自会攀爬的植物——爬山虎。 大家都知道,爬墙高手爬山虎能在各种复杂墙面轻松生长攀爬,可现有的攀爬机器人在复杂…...
Spring AI Alibaba示例项目深度解析:dashscope-audio子模块详解
Spring AI Alibaba示例项目深度解析:dashscope-audio子模块详解 一、模块定位与核心价值 1.1 功能定位 • 音频处理核心组件:基于阿里云DashScope平台实现STT(语音识别)和TTS(文生语音)双模态能力 • 企业级解决方案:提供同步/异步/流式三种调用范式,适配不同业务场景…...
Linux 下 日志系统搭建全攻略
目录 一、引言 二、日志系统基础 日志级别 日志输出格式 三、创建日志所需函数 认识可变参数 编辑 获取时间的函数 小结 四、创建日志 一、引言 在 Linux 环境中开发 C/C 程序时,日志系统是不可或缺的一部分。它不仅有助于调试程序、排查问题ÿ…...
前端布局难题:父元素padding导致子元素无法全屏?3种解决方案
大家好,我是一诺。今天要跟大家分享一个我在实际项目中经常用到的CSS技巧——如何让子元素突破父元素的padding限制,实现真正的全屏宽度效果。 为什么会有这个需求? 记得我刚入行的时候,接到一个需求:要在内容区插入…...
写.NET可以指定运行SUB MAIN吗?调用任意一个里面的类时,如何先执行某段初始化代码?
VB.NET 写.NET可以指定运行SUB MAIN吗?调用任意一个里面的类时,如何先执行某段初始化代码? 分享 1. 在 VB.NET 中指定运行 Sub Main 在 VB.NET 里,你能够指定 Sub Main 作为程序的入口点。下面为你介绍两种实现方式: 方式一:在项目属性…...
蓝桥杯单片机频率
long int Freq; unsigned int Timer_1000Ms; 加上 TMOD | 0x05; void Timer0Init(void) //0毫秒12.000MHz {AUXR & 0x7F; //定时器时钟12T模式TMOD & 0xF0; //设置定时器模式TMOD | 0x05;TL0 0x00; //设置定时初值TH0 0x00; //设置定时初值TF0 0; //清除TF0标…...
word导出PDF老是目录格式变化的问题
这里是写给和我一样的笨蛋的经验帖,适合试了很多网上的经验,结果都用不成的傻瓜蛋,先说好,我是傻瓜蛋,我不是在攻击谁,我们只是客观的,缺根弦罢了。 这些帖子里讲的最多的应该是:“…...
P1577 切绳子(二分)
题目描述 有 N 条绳子,它们的长度分别为 Li。如果从它们中切割出 K 条长度相同的绳子,这 K 条绳子每条最长能有多长?答案保留到小数点后 2 位(直接舍掉 2 位后的小数)。 输入格式 第一行两个整数 N 和 K,接下来 N 行…...
高级:分布式系统面试题精讲
一、引言 分布式系统在现代软件开发中占据重要地位,其设计和实现需要考虑多个关键因素。面试官通过相关问题,考察候选人对分布式系统核心概念的理解、实际应用能力以及在复杂场景下的问题解决能力。本文将深入分析分布式系统的CAP定理、一致性协议、分布…...
【速写】SFT案例实操(以Qwen2.5-instruct-0.5B)
参考资料: https://openbayes.com/console/bbruceyuan/containers/OPg9Oo99ET6https://www.bilibili.com/video/BV1NM1tY3Eu5 LoRA微调案例 首先还是要安装: !pip install -q accelerate peft bitsandbytes transformers sentencepiece !pip install…...
springboot457-库存管理系统(源码+数据库+纯前后端分离+部署讲解等)
💕💕作者: 爱笑学姐 💕💕个人简介:十年Java,Python美女程序员一枚,精通计算机专业前后端各类框架。 💕💕各类成品Java毕设 。javaweb,ssm…...
Node.js中间件的分类
目录 Node.js 中间件的分类与详细介绍 1. 目录结构 2. Express 中间件的主要分类 3. 代码实现 1. 应用级中间件(作用于整个应用) 示例:日志记录中间件 2. 路由级中间件(仅作用于特定路由) 示例:身份…...
棒球规则快速入门·棒球1号位
棒球规则快速入门: 得分方式 进攻方击球后,依次跑过一、二、三垒并返回本垒得1分。若击球直接飞出外场围栏(全垒打),击球员和已上垒的跑垒员均可得分。 比赛结构 共9局,每局分上下半场,双方各…...
【深度学习】通过colab将本地的数据集上传到drive
本地数据集上传到colab很慢,而且断开后就没了,因此通过colab将本地的数据集上传到drive,即使断开连接,第二次连接后挂载drive后即可直接使用数据集。 步骤一、将本地数据集上传到colab的临时文件夹中,由于将文件夹上传…...
MYSQL 存储引擎 和 日志
存储引擎 InnoDB 支持行级别的锁粒度,MyISAM 不支持,只支持表级别的锁粒度。MyISAM 不提供事务支持。InnoDB 提供事务支持,实现了 SQL 标准定义了四个隔离级别。MyISAM 不支持外键,而 InnoDB 支持。MyISAM 不支持 MVCC,…...
【2022】【论文笔记】太赫兹量子阱——
前言 类型 太赫兹 + 量子阱 太赫兹 + 量子阱 太赫兹+量子阱 期刊 红外与毫米波学报 红外与毫米波学报 红外与毫米波学报 作者 张真真 ,...
【NLP 面经 7、常见transformer面试题】
目录 1. 为何使用多头注意力机制? 2. Q和K使用不同权重矩阵的原因 3. 选择点乘而非加法的原因 4. Attention进行scaled的原因 5. 对padding做mask操作 6. 多头注意力降维原因 7. Transformer Encoder模块简介 8. 乘以embedding size的开方的意义 9. 位置编码 10. 其…...
在js中数组相关用法讲解
数组 uniqueArray 简单数组去重 /*** 简单数组去重* param arr* returns*/ export const uniqueArray <T>(arr: T[]) > [...new Set(arr)];const arr1 [1,1,1,1 2, 3];uniqueArray(arr); // [1,2,3]uniqueArrayByKey 根据 key 数组去重 /*** 根据key数组去重* …...
第四章 react-redux,@reduxjs/toolkit依赖,学习
redux系列文章目录 第一章 简单学习redux,单个reducer 第二章 简单学习redux,多个reducer 第三章 redux和react-redux,reduxjs/toolkit依赖结合使用 第五章 两张图告诉你redux常使用的api有哪些 前言 本章将使用react-redux,reduxjs/toolkit依赖创…...
雅思7分听说读写专项书籍推荐
对于目标 7分以上的雅思考生(中高级水平),选对资料真的事半功倍。 下面按照 听力、阅读、写作、口语、综合书籍 五大类来分别列举高分推荐书籍,每本书包括:适合人群、核心内容、推荐理由,并贴合7分目标。 …...
C++容器使用说明
C标准库提供了多种容器,分为序列容器、关联容器、无序关联容器、容器适配器及其他相关类型。以下是所有标准容器的分类及简要说明: 1. 序列容器(Sequence Containers) 按线性顺序存储元素,支持随机或顺序访问。 vecto…...
Python-函数
1. 函数基础 1.1 定义函数 在Python中,使用def关键字来定义函数: def greet():"""简单的问候函数"""print("Hello, World!")1.2 调用函数 定义函数后,可以通过函数名加括号来调用: …...
【Redis】数据的淘汰策略
目录 淘汰策略方案(8种) LRU和LFU策略的区别 使用建议 手搓LRU算法 方式一 方式二 大家好,我是jstart千语。今天和大家回来聊一下redis,这次要讲的是它的淘汰策略。为什么需要淘汰策略呢,就是当redis里面的内存占…...
第七章:从类库到服务的分布式基石_《凤凰架构:构建可靠的大型分布式系统》
第七章:从类库到服务的分布式基石 一、服务发现(Service Discovery) 核心目标:解决分布式系统中服务实例动态变化时如何定位可用服务的问题。 1. 服务发现的意义 动态环境挑战: 微服务架构中,服务实例的…...
spring-ai-alibaba第九章使用Milvus构建大模型RAG应用
1、pom文件 <dependencies><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter</artifactId><version>${spring-ai-alibaba.version}</version></dependency><dependency&g…...
手撕LLM(一):从源码出发,探索LLM推理全流程
2025年,大模型爆发元年,各种各样的大模型、框架、工具层出不穷,不断刷新人们应用大模型的门槛,短短10行代码,就能完成“加载模型加载数据集推理强化学习”的全流程训练,但其底层的运行机制也被高度抽象的接…...
讯飞语音听写(流式版)开发指南
语音交互大模型的功能越来越受到重视。讯飞语音听写(流式版)为开发者提供了一种高效、准确的语音识别解决方案。本文将基于 Home.vue、iat_xfyun.js 和 sparkChat.js 这三个文档,详细阐述讯飞语音听写(流式版)的开发逻…...
P3654 First Step (ファーストステップ)
题目描述 可是……这个篮球场,好像很久没有使用过的样子啊…… 里面堆满了学校的各种杂物呢…… 我们 Aqours 的成员要怎么在里面列队站下呢? 我们浦之星女子学院的篮球场是一个 R 行 C 列的矩阵,其中堆满了各种学校的杂物 (用 # 表示)&a…...
MySQL篇(六)MySQL 分库分表:应对数据增长挑战的有效策略
MySQL篇(六)MySQL 分库分表:应对数据增长挑战的有效策略 MySQL篇(六)MySQL 分库分表:应对数据增长挑战的有效策略一、引言二、为什么需要分库分表2.1 性能瓶颈2.2 存储瓶颈2.3 高并发压力 三、分库分表的方…...
SonarQube 配置SQL Server 数据库遇到的问题
之前本机跑了一套SonarQube的社区版,默认使用的是H2数据库,那么我把它练到我机器上的SQL Server数据库了,期间遇到以下两个问题,并在配置过程中解决掉,特将这个过程记录下来。 一、JDBC连接SQL Server问题 1. 问题出…...
23种设计模式-行为型模式-备忘录
文章目录 简介问题解决代码关键实现要点功能扩展方向 总结 简介 备忘录是一种行为设计模式, 允许在不暴露对象实现细节的情况下保存和恢复对象之前的状态。 问题 假如你正在开发一款文字编辑器应用。你想加入撤销功能。你可以采用直接的方式来实现: 程序在执行任…...
IDEA/WebStrom操作之commit前批量清除console.log()与debugger
前言: 在前端开发过程中,往往需要频繁用到console.log()与debugger,来观察数据具体情况以及断点调试。在经历了水生火热的开发动作后,往往会残留一地console.log()和debugger,若开发者还得手动在多个文件中一个个去除…...
每日算法-250405
34. 在排序数组中查找元素的第一个和最后一个位置 题目 思路 本题的核心思路是二分查找。 解题过程 问题分析:在一个升序排列的数组中查找一个目标值 target 的起始和结束位置。这是一个典型的二分查找应用场景。核心转换:题目要求找到 target 的第一个…...
设计模式简述(四)模板方法模式
模板方法模式 描述基本定义使用 描述 当一系列业务的基本流程是相同的,对于不同的业务可以在各自子类实现 所谓模板方法指的就是父类中固定的那部分代码 其实这里的思想和前面设计原则中开闭原则的描述是一致的,父类中的模板代码就是稳定的部分&#x…...
论文修改时有哪些需要注意的问题?
论文修改是学术写作中不可或缺的环节,直接影响成果的专业性和说服力。许多作者因忽略细节或急于定稿,导致论文质量大打折扣。那么,如何修改才能提升论文的严谨性与可读性呢? 一、逻辑结构 论文修改时,先从头到尾通读…...
JAVA阻塞队列
目录 一、什么是阻塞队列?特点是什么? 二、阻塞队列的两种创建方式: 1、使用 ArrayBlockingQueue<>( ) : 2、使用 LinkedBlockingQueue<>( ) : 三、阻塞队列方法的使用: 阻塞队列关键的两个方法&…...