第六章 QT基础:7、Qt中多线程的使用
在进行桌面应用程序开发时,假设应用程序需要处理比较复杂的逻辑,如果只有一个线程去处理,就会导致窗口卡顿,无法处理用户的相关操作。
这种情况下,需要使用多线程:
- 主线程处理窗口事件和控件更新
- 子线程进行后台逻辑处理
- 多线程协作提升用户体验和执行效率
多线程开发注意事项
- Qt默认的线程叫做窗口线程(主线程),负责处理窗口控件和界面更新。
- 子线程负责后台的业务逻辑,子线程中不能直接操作窗口控件。
- 主线程和子线程之间的数据通信,使用信号与槽机制完成。
1. 线程类 QThread
Qt 提供了 QThread
类来创建子线程,有两种常用的子线程使用方式。
1.1 常用成员函数
// 构造函数,创建一个线程对象
QThread::QThread(QObject *parent = Q_NULLPTR);// 查询线程是否结束(任务执行完毕)
bool QThread::isFinished() const;// 查询线程是否正在运行
bool QThread::isRunning() const;// 设置和获取线程优先级
Priority QThread::priority() const;
void QThread::setPriority(Priority priority);// 退出线程(退出事件循环)
void QThread::exit(int returnCode = 0);// 等待线程结束(通常配合exit()使用)
bool QThread::wait(unsigned long time = ULONG_MAX);
1.2 信号与槽
// 请求线程正常退出(发送退出指令)
[slot] void QThread::quit();// 启动线程,内部自动调用run()
[slot] void QThread::start(Priority priority = InheritPriority);// 强制终止线程(不推荐,可能导致资源泄漏)
[slot] void QThread::terminate();// 线程执行完成时发出的信号
[signal] void QThread::finished();// 线程开始运行时发出的信号
[signal] void QThread::started();
1.3 静态函数
// 获取当前执行的线程指针
[static] QThread* QThread::currentThread();// 获取当前系统的理想线程数(通常等于CPU核心数)
[static] int QThread::idealThreadCount();// 线程休眠函数
[static] void QThread::msleep(unsigned long msecs); // 毫秒级休眠
[static] void QThread::sleep(unsigned long secs); // 秒级休眠
[static] void QThread::usleep(unsigned long usecs); // 微秒级休眠
1.4 任务处理函数
// 子线程逻辑的入口函数,需要重写
[virtual protected] void QThread::run();
- 注意
run()
是 虚函数,只能通过子类重写。 - 不要手动调用
run()
,应通过start()
启动线程,让Qt自动调用run()
。
2. 使用方式一:继承QThread重写run()
2.1 操作步骤
[!important]
- 创建一个子类继承自
QThread
- 重写
run()
函数,写入业务逻辑- 在主线程中 new 子线程对象
- 调用
start()
启动子线程
2.2 示例代码(含详细注释)
mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H#include <QThread>// 自定义线程类,继承自QThread
class MyThread : public QThread
{Q_OBJECT
public:explicit MyThread(QObject *parent = nullptr); // 构造函数protected:void run() override; // 重写run(),处理子线程任务//子线程的`run()`是由系统自动调用的,不应该让别人直接调用,否则容易破坏线程机制signals:void curNumber(int num); // 自定义信号,用于传递当前数字
};#endif // MYTHREAD_H
mythread.cpp
#include "mythread.h"
#include <QDebug>MyThread::MyThread(QObject *parent) : QThread(parent) {}
//第一个MyThread::是定义的是属于 `MyThread` 这个类的东西
//第二个MyThread构造函数的名字,在C++里构造函数名字必须和类名一模一样void MyThread::run()
{qDebug() << "当前线程对象地址:" << QThread::currentThread();int num = 0;while (1){emit curNumber(num++); // 每次加一并发出信号if (num == 10000000) // 数到一定数量退出break;QThread::usleep(1); // 每次循环稍作休眠,减少CPU占用}qDebug() << "run()执行完毕,子线程退出...";
}
mainwindow.cpp
#include "mainwindow.h" // 引入主窗口头文件
#include "ui_mainwindow.h" // 引入主窗口UI界面头文件
#include "mythread.h" // 引入自定义线程类头文件
#include <QDebug> // 引入Qt调试输出模块// 主窗口的构造函数
// 使用初始化列表,调用父类QMainWindow的构造函数MainWindow,并传入parent对象指针
//parent的主要作用是建立父子对象关系,方便自动内存管理!
MainWindow::MainWindow(QWidget *parent)//子类名::构造函数名(参数): QMainWindow(parent), // 1. 调用父类QMainWindow的构造函数,传入parentui(new Ui::MainWindow) // 2. 初始化成员变量ui,new出一个新的Ui::MainWindow对象
{ui->setupUi(this); // 3. 在构造体内部,初始化界面// 输出当前线程对象的地址// QThread::currentThread() 返回当前正在运行的线程指针qDebug() << "主线程对象地址: " << QThread::currentThread();// 创建自定义子线程对象// 注意:这里没有设置父对象,生命周期需要自己管理,或合理搭配QObject父子机制MyThread* subThread = new MyThread;// 连接子线程发出的curNumber信号到主线程的槽函数(用lambda表达式)// 作用:收到子线程发的数字信号后,更新UI界面label上的数值connect(subThread, &MyThread::curNumber, this, [=](int num){ui->label->setNum(num); // 把收到的数字设置到界面上的label控件});// 连接“开始”按钮的点击信号到槽函数(用lambda表达式)// 作用:点击按钮时启动子线程connect(ui->startBtn, &QPushButton::clicked, this, [=](){subThread->start(); // 启动子线程,内部自动调用子线程的run()方法});
}// 主窗口析构函数
// 作用:释放UI资源
MainWindow::~MainWindow()
{delete ui;
}
3. 使用方式二:QObject+moveToThread()
3.1 操作步骤
[!important]
- 创建一个普通类继承自
QObject
- 定义公共函数作为业务处理函数(如 working)
- 创建
QThread
对象- 创建工作对象(不要设置父对象)
- 使用
moveToThread()
把工作对象移到子线程- 启动子线程,绑定信号槽调用工作函数
3.2 示例代码(含详细注释)
mywork.h
#ifndef MYWORK_H
#define MYWORK_H#include <QObject>// 自定义工作对象
class MyWork : public QObject
{Q_OBJECT
public:explicit MyWork(QObject *parent = nullptr);void working(); // 工作逻辑函数signals:void curNumber(int num); // 自定义信号传递当前数字
};#endif // MYWORK_H
mywork.cpp
#include "mywork.h" // 引入自定义工作类头文件
#include <QDebug> // 引入Qt调试打印模块
#include <QThread> // 引入Qt线程模块,使用currentThread()和usleep()// 构造函数实现
// 使用初始化列表方式,调用父类QObject的构造函数,传入parent指针
MyWork::MyWork(QObject *parent) : QObject(parent) {}// 自定义的工作函数,具体执行子线程任务
void MyWork::working()
{// 打印当前执行working()的线程对象指针// QThread::currentThread()是静态函数,返回当前运行线程的指针qDebug() << "当前线程对象地址:" << QThread::currentThread();int num = 0; // 定义计数变量,从0开始// 无限循环while (1){//在子线程里处理数据后,及时把处理结果发送(通知)给主线程。emit curNumber(num++); // 每次计数后,发射curNumber信号,把当前num值发出去// 如果计数到10000000,跳出循环,结束工作if (num == 10000000)break;QThread::usleep(1); // 休眠1微秒,避免CPU占用过高(防止死循环卡死)}// 循环结束,任务完成,打印提示qDebug() << "working()执行完毕,子线程退出...";
}
mainwindow.cpp
#include "mainwindow.h" // 引入主窗口头文件
#include "ui_mainwindow.h" // 引入自动生成的UI界面头文件
#include <QThread> // 引入Qt线程模块
#include "mywork.h" // 引入自定义工作类头文件
#include <QDebug> // 引入Qt调试打印模块// 主窗口构造函数
// 使用初始化列表调用父类QMainWindow构造函数,并创建UI对象
MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this); // 初始化界面控件// 打印当前线程对象地址(主线程)qDebug() << "主线程对象地址:" << QThread::currentThread();// 创建子线程对象(QThread对象)QThread* sub = new QThread;// 创建工作对象(自定义的MyWork类实例)// 注意:不能设置parent,否则moveToThread会失败!MyWork* work = new MyWork;// 将工作对象移动到子线程中执行// 注意:只能移动继承自QObject的对象work->moveToThread(sub);// 启动子线程// 此时QThread内部开启一个空事件循环(event loop),为工作对象提供子线程环境sub->start();// 连接按钮点击信号到工作对象的working槽函数// 作用:点击按钮后,让work开始执行working()方法connect(ui->startBtn, &QPushButton::clicked, work, &MyWork::working);//connect(发送者, 发送者的信号, 接收者, 接收者的槽函数);//&MyWork::working指向 `MyWork` 类的成员函数 `working()`//- Qt在不同线程之间发信号自动切换线程(通过队列连接QueueConnection)。 //- 子线程不能直接操作界面,但发信号给主线程处理是安全的!// 连接工作对象发出的curNumber信号到主线程的槽// 作用:收到子线程发回的数字后,在界面label上显示connect(work, &MyWork::curNumber, this, [=](int num){ui->label->setNum(num);});
}// 主窗口析构函数
// 释放UI资源
MainWindow::~MainWindow()
{delete ui;
}
connect(ui->startBtn, &QPushButton::clicked, work, &MyWork::working);
![[Pasted image 20250428134905.png]]
connect(work, &MyWork::curNumber, this, [=](int num){ui->label->setNum(num);
});
![[Pasted image 20250428134855.png]]
4. 小结
使用方式 | 优点 | 缺点 |
---|---|---|
继承QThread重写run | 简单直观,适合小任务 | run()过于臃肿时维护困难 |
QObject+moveToThread | 灵活,适合多个任务类 | 写法复杂,要求掌握对象迁移 |
5. 版权信息
- 作者: 苏丙榅
- 链接: https://subingwen.cn/qt/thread/#3-2-示例代码
- 来源: 爱编程的大丙
- 版权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。
✅ 示例场景:多线程文件拷贝(防止界面卡顿)
copyworker.h
#ifndef COPYWORKER_H
#define COPYWORKER_H#include <QObject>class CopyWorker : public QObject
{Q_OBJECT
public:explicit CopyWorker(QObject *parent = nullptr);void setFilePaths(const QString &src, const QString &dest);public slots:void startCopy(); // 复制操作入口(槽函数)signals:void progress(int percent); // 进度更新信号void finished(); // 完成信号void error(QString msg); // 错误信息
private:QString m_srcFilePath;QString m_destFilePath;
};#endif // COPYWORKER_H
copyworker.cpp
#include "copyworker.h"
#include <QFile>
#include <QFileInfo>
#include <QThread>CopyWorker::CopyWorker(QObject *parent): QObject(parent)
{}void CopyWorker::setFilePaths(const QString &src, const QString &dest)
{m_srcFilePath = src;m_destFilePath = dest;
}void CopyWorker::startCopy()
{QFile srcFile(m_srcFilePath);QFile destFile(m_destFilePath);if (!srcFile.open(QIODevice::ReadOnly)) {emit error("源文件无法打开!");return;}if (!destFile.open(QIODevice::WriteOnly)) {emit error("目标文件无法创建!");return;}QFileInfo info(srcFile);qint64 totalSize = info.size();qint64 copied = 0;const qint64 bufferSize = 1024 * 1024; // 1MB缓冲while (!srcFile.atEnd()) {QByteArray data = srcFile.read(bufferSize);destFile.write(data);copied += data.size();int percent = static_cast<int>((copied * 100.0) / totalSize);emit progress(percent); // 发射当前进度QThread::msleep(50); // 模拟耗时}srcFile.close();destFile.close();emit finished(); // 复制完成信号
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "copyworker.h"#include <QThread>
#include <QFileDialog>
#include <QMessageBox>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);// 创建线程和工作对象QThread* thread = new QThread(this);CopyWorker* worker = new CopyWorker;worker->moveToThread(thread);connect(ui->btnSelectFile, &QPushButton::clicked, this, [=] {QString file = QFileDialog::getOpenFileName(this, "选择源文件");ui->lineEditSource->setText(file);});connect(ui->btnSelectTarget, &QPushButton::clicked, this, [=] {QString file = QFileDialog::getSaveFileName(this, "选择目标路径");ui->lineEditDest->setText(file);});connect(ui->btnStartCopy, &QPushButton::clicked, this, [=] {QString src = ui->lineEditSource->text();QString dest = ui->lineEditDest->text();if (src.isEmpty() || dest.isEmpty()) {QMessageBox::warning(this, "提示", "请填写完整路径");return;}worker->setFilePaths(src, dest);emit startWork(); // 发出信号让子线程开始执行});// 绑定信号到槽函数(使用队列连接,线程安全)connect(this, &MainWindow::startWork, worker, &CopyWorker::startCopy);connect(worker, &CopyWorker::progress, this, [=](int p){ui->progressBar->setValue(p);});connect(worker, &CopyWorker::finished, this, [=]{QMessageBox::information(this, "完成", "文件复制完成!");});connect(worker, &CopyWorker::error, this, [=](const QString &msg){QMessageBox::critical(this, "错误", msg);});thread->start(); // 启动线程
}MainWindow::~MainWindow()
{delete ui;
}
mainwindow.h
信号声明
signals:void startWork(); // 让子线程开始执行的信号
UI界面组件要求
lineEditSource
:显示源路径lineEditDest
:显示目标路径btnSelectFile
:选择源文件按钮btnSelectTarget
:选择目标按钮btnStartCopy
:启动复制按钮progressBar
:进度条(范围0~100)
✅ 技术要点总结
技术点 | 说明 |
---|---|
QThread + QObject | 实现真正的工作线程架构 |
moveToThread() | 将工作对象迁移到线程中 |
信号槽机制 | 主线程与子线程通信(线程安全) |
UI线程与逻辑分离 | 不阻塞界面,提升用户体验 |
线程安全UI更新 | 使用信号更新界面,避免子线程直接操作控件 |
相关文章:
第六章 QT基础:7、Qt中多线程的使用
在进行桌面应用程序开发时,假设应用程序需要处理比较复杂的逻辑,如果只有一个线程去处理,就会导致窗口卡顿,无法处理用户的相关操作。 这种情况下,需要使用多线程: 主线程处理窗口事件和控件更新子线程进…...
前端Vue3 + 后端Spring Boot,前端取消请求后端处理逻辑分析
在 Vue3 Spring Boot 的技术栈下,前端取消请求后,后端是否继续执行业务逻辑的答案仍然是 取决于请求处理的阶段 和 Spring Boot 的实现方式。以下是结合具体技术的详细分析: 1. 请求未到达 Spring Boot 场景:前端通过 AbortContr…...
ShaderToy学习笔记 05.3D旋转
1. 3D旋转 1.1. 汇制立方体 由于立方体没有旋转,所以正对着看过去时,看起来是正方形的,所以需要旋转一下,才能看到立方体的样子。 常见几何体的SDF BOX 的SDF为 float sdBox( vec3 p, vec3 b ) {vec3 q abs(p) - b;return len…...
编程日志4.24
栈的链表基础表示结构 #include<iostream> #include<stdexcept> using namespace std; //模板声明,表明Stack类是一个通用的模板,可以用于存储任何类型的元素T template<typename T> //栈的声明 //Stack类的声明,表示一…...
通信设备制造数字化转型中的创新模式与实践探索
在数字化浪潮下,通信设备制造企业积极探索创新模式,推动数字化转型,以提升竞争力和适应市场变化。 在生产模式创新方面,企业引入工业互联网平台,实现设备互联互通与生产过程智能化监控。通过在生产设备上安装传感器&a…...
同一个路由器接口eth0和ppp0什么不同?
答案摘自 百度知道, eth0是以太网接口,是表示以太网连接的物理接口,路由器可能会有不止一个以太网接口,因此可能会eth0,eht1之类的。 ppp0是经以太网接口PPP拨号时创建的链路接口,用以建PPP拨号连接的&am…...
零训练成本优化LLM: 11种LLM权重合并策略原理与MergeKit实战配置
随着大语言模型的快速发展,如何在不消耗大量计算资源的情况下优化模型性能成为业界关注焦点。模型权重合并技术提供了一种零训练成本的高效解决方案,能够智能整合多个专业微调模型的优势,无需额外训练即可显著提升性能表现。本文系统剖析11种…...
基于tabula对pdf中多个excel进行识别并转换成word中的优化(五)
优化地方:处理合并的单元格内容。 1、修改为stream"complex" 2、增加换行符f"{table_data[i - 1][j]}\n{table_data[i][j]}".strip() 一、pdf中excel样例 二、完整代码 import tabula import numpy as np from docx import Document from docx…...
QT中的网络编程
Qt中的网络编程是通过封装操作系统的API进行实现的 C标准库中,并没有提供网络编程的封装接口 进行网络编程时本质是在编写应用层代码,需要传输层提供支持 传输层最核心的协议为UDP/TCP 使用Qt网络编程的API时,需要在.pro文件中添加network模块…...
0.5 像素边框实现
0.5 像素边框怎么实现 文章目录 0.5 像素边框怎么实现方法 1:使用 transform: scale() 缩放(推荐)方法 2:直接使用 0.5px 边框(部分浏览器支持)方法 3:使用 box-shadow 模拟边框方法 4ÿ…...
【Vagrant+VirtualBox创建自动化虚拟环境】Ansible测试Playbook
文章目录 Vagrant安装vagrant安装 VirtualBox如何使用 Ansible安装AnsiblePlaybook测试创建hosts文件创建setup.yml文件 Vagrant Vagrant是一个基于Ruby的工具,用于创建和部署虚拟化开发环境。它使用Oracle的开源VirtualBox虚拟化系统,使用 Chef创建自动…...
“连接世界的桥梁:深入理解计算机网络应用层”
一、引言 当你浏览网页、发送邮件、聊天或观看视频时,这一切都离不开计算机网络中的应用层(Application Layer)。 应用层是网络协议栈的最顶层,直接为用户的各种应用程序提供服务。它为用户进程之间建立通信桥梁,屏蔽了…...
Vulkan与OpenGL的对比
传统图形API与现代图形API 传统图形API指的是OpenGL/DirectX11这类简单易用、驱动托管严重的图形接口;而现代图形API则指的是Vulkan/Metal/DirectX12这类使用复杂、暴露更多底层硬件功能来显式控制的弱驱动设计的图形接口。 现代图形API与传统图形API相比ÿ…...
海外社交App的Web3革命:去中心化社交与Token经济实战指南
一、Web3社交的核心组件:从身份到经济的重构 去中心化身份(DID)技术栈:Ceramic IDX协议构建链上身份图谱代码示例:javascript// 创建DID const ceramic new CeramicClient() const did new DID({ provider: cerami…...
凯撒密码算法的实现
在密码学里,凯撒密码(也叫恺撒密码、移位密码、恺撒代码或者恺撒移位)是一种简单且广为人知的加密技术。它属于替换密码的一种,在这种加密方式中,明文中的每个字母都会被替换成字母表中往后移动固定位数的字母。例如&a…...
Chrome的插件扩展程序安装目录是什么?在哪个文件夹?
目录 前提 直接复制到浏览器中打开 Mac下Chrome extension 安装路径 最近换了mac pro用起来虽然方便,但是对常用的一些使用方法还是不熟悉。这不为了找到mac上chrome插件的安装路径在哪里,花费了不少时间。我想应用有不少像小编一样刚刚使用mac的小白…...
C++23中的std::forward_like:完美转发的增强
文章目录 一、背景与动机(一)完美转发的局限性(二)std::forward_like的提出 二、std::forward_like的设计与实现(一)基本语法(二)实现原理(三)与std::forward…...
AI与软件测试的未来:如何利用智能自动化改变测试流程
用工作流生成测试用例和自动化测试脚本! 随着人工智能(AI)技术的迅猛发展,软件测试作为软件开发生命周期中的关键环节,正在经历一场前所未有的变革。传统的测试方法已经无法满足现代快速迭代和持续交付的需求ÿ…...
React Native 动态切换主题
React Native 动态切换主题 创建主题配置和上下文创建主题化高阶组件主应用组件主屏幕组件(类组件形式) 创建主题配置和上下文 // ThemeContext.jsimport React, { Component, createContext } from react;import { Appearance, AsyncStorage } from rea…...
得物 小程序 6宫格 分析
声明 本文章中所有内容仅供学习交流使用,不用于其他任何目的,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关! 逆向过程 部分python代码 if result …...
PocketFlow一个最小的Agent框架
1、背景 PocketFlow 2、使用 python 的版本需要python3.10 在cookbook中有如何使用的说明,如图所示 在tuils.py中修改代码 def call_llm(messages):# client OpenAI(api_keyos.environ.get("OPENAI_API_KEY", "your-api-key"))client Op…...
Objective-C Block 底层原理深度解析
Objective-C Block 底层原理深度解析 1. Block 是什么? 1.1 Block 的本质 Block 是 Objective-C 中的特殊对象,实现了匿名函数的功能 通过 isa 指针继承自 NSObject,可以响应(如 copy、retain、release)等内存管理方…...
AlDente Pro for Mac电脑 充电限制保护工具 安装教程【简单,轻松上手】
AlDente Pro for Mac电脑 充电限制保护工具 安装教程【简单,轻松上手】 AlDente Pro for Mac,是一款充电限制保护工具,是可以限制最大充电百分比来保护电池的工具。锂离子和聚合物电池(如 MacBook 中的电池)在40&…...
Linux systemd 从理论到实践:现代系统管理的核心工具
文章目录 引言:为什么需要 systemd?第一部分:systemd 核心理论1.1 systemd 的设计哲学1.2 核心组件1.3 单元文件(Unit File)结构 第二部分:实战操作指南2.1 基础命令2.2 服务管理高级操作2.3 日志管理&…...
分享一个移动端项目模板:React-Umi4-mobile
分享一个移动端项目模板:React-Umi4-mobile 大家好,今天想和大家分享一个我最近做的移动端项目模板 React-Umi4-mobile。 模板的主要内容 这个模板主要包括: 基于 Umi 4 框架使用了 antd-mobile 组件库配置了 px 自动转 vw(基…...
Tailwind CSS 响应式设计解析(含示例)
本文内容: Tailwindcss V4 中如何使用响应式设计功能,包括默认断点、自定义断点、断点范围控制以及容器查询的各种技巧,帮助你在不离开 HTML 的前提下优雅构建响应式页面。 🌟 默认断点用法(移动优先) Tail…...
ElasticSearch入门
1 elasticsearch概述 1.1 elasticsearch 简介 官网: https://www.elastic.co/ ElasticSearch是一个基于 Lucene 的搜索服务器,基于RESTful web接口。Elasticsearch是用Java开发的,开源的企业级搜索引擎。 Elastic官方宣布Elasticsearch进入Version 8…...
强化学习之基于无模型的算法之时序差分法
2、时序差分法(TD) 核心思想 TD 方法通过 引导值估计来学习最优策略。它利用当前的估计值和下一个时间步的信息来更新价值函数, 这种方法被称为“引导”(bootstrapping)。而不需要像蒙特卡罗方法那样等待一个完整的 episode 结束才进行更新&…...
【网络原理】TCP异常处理(二):连接异常
目录 一. 由进程崩溃引起的连接断开 二. 由关机引起的连接断开 三. 由断电引起的连接断开 四. 由网线断开引起的连接断开 一. 由进程崩溃引起的连接断开 在一般情况下,进程无论是正常结束,还是异常崩溃,都会触发回收文件资源,…...
[stm32] 4-1 USART(1)
文章目录 前言4-1 USARTUSART简介什么是USART?USART名字的含义?如何使用USART? USART的工作原理什么是串并转换?为什么要进行串并转换?移位寄存器串并行转换电路 USART寄存器组和完整框图 前言 本笔记内容,为本人依据…...
C++多线程与锁机制
1. 基本多线程编程 1.1 创建线程 #include <iostream> #include <thread>void thread_function() {std::cout << "Hello from thread!\n"; }int main() {std::thread t(thread_function); // 创建并启动线程t.join(); // 等待线程结束return 0; …...
【MCP Node.js SDK 全栈进阶指南】高级篇(4):自定义传输层开发
引言 在MCP(Model Context Protocol)应用开发中,传输层是连接客户端与服务器的关键环节,直接影响应用的性能、可靠性和扩展性。默认的传输方式虽然能满足基本需求,但在复杂场景下,自定义传输层能够为应用提供更高的灵活性和优化空间。本文将深入探讨MCP TypeScript-SDK中…...
当向量数据库与云计算相遇:AI应用全面提速
如果将AI比作一台高速运转的机器引擎,那么数据便是它的燃料。 然而,存储数据的燃料库--传统数据库,在AI时代的效率瓶颈愈发明显,已经无法满足AI对于数据的全新需求。 因此,向量数据库近年来迅速崛起。向量数据库通过…...
【2024-NIPS-版权】Evaluating Copyright Takedown Methods for Language Models
1.背景 目前 LLMs 在训练过程中使用了大量的受版权保护数据,这些数据会导致大模型记忆并生成与训练数据相似的内容,从而引发版权问题。随着版权所有者对模型训练和部署中的版权问题提起诉讼(例如 Tremblay v. OpenAI, Inc. 和 Kadrey v. Met…...
【PyTorch动态计算图原理精讲】从入门到灵活应用
目录 前言技术背景与价值当前技术痛点解决方案概述目标读者说明一、技术原理剖析核心概念图解核心作用讲解关键技术模块说明技术选型对比二、实战演示环境配置要求核心代码实现案例1:基础计算图构建案例2:条件分支动态图案例3:循环结构动态图运行结果验证三、性能对比测试方…...
阿里巴巴Qwen3发布:登顶全球开源模型之巅,混合推理模式重新定义AI效率
今天凌晨,阿里巴巴正式开源了新一代通义千问大模型Qwen3,这一举措不仅标志着国产大模型技术的又一里程碑,更以“混合推理”“极致性能”“超低成本”三大核心优势,刷新了全球开源模型的竞争格局。Qwen3在多项评测中超越DeepSeek-R…...
5. 配置舵机ID(具身智能机器人套件)
1. 连接舵机 waveshare驱动器板使用9-12v供电Type-C连接电脑DVG连接一个舵机 2. 使用FT SCServo Debug软件 设置串口设置波特率(默认1000000,100万)打开串口编程界面修改ID 3. 依次修改所有舵机ID 分别使用waveshare驱动板连接舵机&…...
Nacos源码—2.Nacos服务注册发现分析四
大纲 5.服务发现—服务之间的调用请求链路分析 6.服务端如何维护不健康的微服务实例 7.服务下线时涉及的处理 8.服务注册发现总结 7.服务下线时涉及的处理 (1)Nacos客户端服务下线的源码 (2)Nacos服务端处理服务下线的源码 (3)Nacos服务端发送服务变动事件给客户端的源码…...
从Windows开发迁移到信创开发的指南:国产替代背景下的技术路径与实践
🧑 博主简介:CSDN博客专家、CSDN平台优质创作者,高级开发工程师,数学专业,10年以上C/C, C#, Java等多种编程语言开发经验,拥有高级工程师证书;擅长C/C、C#等开发语言,熟悉Java常用开…...
从数据到决策:安科瑞EIoT如何让每一度电“清晰可见”?
安科瑞顾强 在能源管理迈向精细化与数字化的今天,安科瑞EIoT能源物联网平台以“数据驱动能源价值”为核心理念,融合物联网、云计算与大数据技术,打通从设备感知到云端决策的全链路闭环,助力工商业企业、园区、物业等场景实现用电…...
10.学习笔记-MyBatisPlus(P105-P110)
1.MyBatisPlus入门案例 (1)MyBatisPlus(简称Mp)是基于MyBatis框架基础上开发的增强型工具,目的是简化开发,提高效率。 (2)开发方式:基于MyBatis使用MyBatisPlusÿ…...
LayerSkip: Enabling Early Exit Inference and Self-Speculative Decoding
TL;DR 2024 年 Meta FAIR 提出了 LayerSkip,这是一种端到端的解决方案,用于加速大语言模型(LLMs)的推理过程 Paper name LayerSkip: Enabling Early Exit Inference and Self-Speculative Decoding Paper Reading Note Paper…...
fastapi和flaskapi有什么区别
FastAPI 和 Flask 都是 Python 的 Web 框架,但设计目标和功能特性有显著差异。以下是它们的核心区别: 1. 性能与异步支持 FastAPI 基于 Starlette(高性能异步框架)和 Pydantic(数据校验库)…...
在 JMeter 中使用 BeanShell 获取 HTTP 请求体中的 JSON 数据
在 JMeter 中,您可以使用 BeanShell 处理器来获取 HTTP 请求体中的 JSON 数据。以下是几种方法: 方法一:使用前置处理器获取请求体 如果您需要在发送请求前访问请求体: 添加一个 BeanShell PreProcessor 到您的 HTTP 请求采样器…...
Go 1.25为什么要废除核心类型
关于核心类型为什么要1.25里要移除,作者Robert在博客Goodbye core types - Hello Go as we know and love it!里给了详细耐心的解答。 背景:Go 1.18 引入了泛型(generics),带来了类型参数…...
flask中的Response 如何使用?
在 Flask 中,Response 对象用于生成 HTTP 响应并返回给客户端。以下是其常见用法及示例: 1. 直接返回字符串或 HTML 视图函数返回的字符串会被自动包装为 Response 对象,默认状态码为 200,内容类型为 text/html: app…...
基于SpringAI实现简易聊天对话
简介 本文旨在记录学习和实践 Spring AI Alibaba 提供的 ChatClient 组件的过程。ChatClient 是 Spring AI 中用于与大语言模型(LLM)进行交互的高级 API,它通过流畅(Fluent)的编程接口,极大地简化了构建聊天…...
STM32单片机入门学习——第49节: [15-2] 读写内部FLASH读取芯片ID
写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做! 本文写于:2025.04.29 STM32开发板学习——第49节: [15-2] 读写内部FLASH&读取芯片ID 前言开发板说…...
第14讲:科研图表的导出与排版艺术——高质量 PDF、TIFF 输出与投稿规范全攻略!
目录 📘 前言:导出,不只是“保存”! 🎯 一、你需要掌握的导出目标 🖼️ 二、TIFF / PNG 导出规范(适用于投稿) 🧲 三、PDF 矢量图导出(排版首选) 🧩 四、强烈推荐组合:showtext + Cairo 🧷 五、多个图的组合导出技巧 🧪 六、特殊投稿需求处理 �…...
SRIO IP调试问题记录(ready信号不拉高情况)
问题:调试过程中遇到有时写入数据后数据不发送,并且ready信号在写入一定数据后一直拉低的情况(偶发,不是每次必然出现)。buf空间设置为16时,写入15包数据,写完第16包包头后,ready信号…...