Qt开发:QThreadPool的介绍和使用

article/2025/6/7 15:08:48

文章目录

    • 一、QThreadPool 简介
    • 二、常用函数简介
    • 三、完整示例

一、QThreadPool 简介

  QThreadPool 是 Qt 提供的用于高效管理线程资源的类。它通过线程池的方式管理和复用线程,适合处理大量、短时间运行的任务,避免频繁创建和销毁线程带来的性能开销。

常用功能:

  • 管理多个可复用的工作线程;
  • 接收任务并调度执行;
  • 与 QRunnable 配合使用;
  • 默认最大线程数为 QThread::idealThreadCount()(通常等于 CPU 核心数);
  • 支持设置最大线程数、自定义线程池等。

二、常用函数简介

2.1 int QThreadPool::activeThreadCount() const
功能说明:返回当前线程池中 正在活动(运行任务) 的线程数。

应用场景:

  • 实时查看线程池运行状态;
  • 调试线程池任务调度情况;
  • 控制提交任务的节奏(例如当前线程数未满才继续添加);
  • 动态 UI 显示线程使用情况(如进度、资源消耗等)。

示例代码:

#include <QThreadPool>
#include <QDebug>void checkActiveThreads() {QThreadPool *pool = QThreadPool::globalInstance();qDebug() << "当前正在运行的线程数:" << pool->activeThreadCount();
}

结合实际使用:

void addTaskIfIdle() {QThreadPool *pool = QThreadPool::globalInstance();if (pool->activeThreadCount() < pool->maxThreadCount()) {// 当前有空闲线程,可以提交新任务MyTask *task = new MyTask();pool->start(task);qDebug() << "已提交新任务,当前活动线程数:" << pool->activeThreadCount();} else {qDebug() << "线程池已满,稍后再试";}
}

注意事项:

  • 线程池是动态调度的,activeThreadCount() 的值可能在多线程环境中随时变化;
  • 此函数是 线程安全的(thread-safe),可放心在多线程场景下调用;
  • 并不能获取待执行任务数量(可使用 QSemaphore 或自己维护队列实现任务计数)。

2.2 void QThreadPool::clear()
功能说明:

  • 从线程池中移除所有等待执行的任务(即任务队列中还未开始运行的任务);
  • 不会中断正在执行的任务;
  • 被清除的任务如果是 setAutoDelete(true),会自动释放内存。

使用场景:
在这里插入图片描述

示例代码:

#include <QThreadPool>
#include <QRunnable>
#include <QDebug>class MyTask : public QRunnable {
public:void run() override {qDebug() << "正在运行任务:" << QThread::currentThread();QThread::sleep(2); // 模拟耗时任务}
};void testClearThreadPool() {QThreadPool *pool = QThreadPool::globalInstance();pool->setMaxThreadCount(2);// 提交5个任务for (int i = 0; i < 5; ++i) {MyTask *task = new MyTask();task->setAutoDelete(true);pool->start(task);}// 清除尚未开始的任务(等待队列中)pool->clear();qDebug() << "已清除未开始执行的任务";
}

注意事项:

  • clear() 只影响还没开始运行的任务;
  • 正在执行的任务不会被打断;
  • 若需要中断正在运行的任务,需要:在任务中定期检查某个取消标志;使用信号控制;或使用 QThread 管理(可中断线程运行);
  • 若任务未设置 setAutoDelete(true),被清除后你需要手动 delete。

2.3 int QThreadPool::expiryTimeout() const
作用:返回线程池中线程的“过期超时(expiry timeout)”值,也就是 线程空闲多久后将自动销毁。

应用背景:

  • Qt 的线程池会自动回收空闲线程以减少资源消耗;
  • expiryTimeout 设置了线程空闲多长时间后自动退出,防止线程常驻内存;
  • 如果线程在 timeout 时间内再次有任务进来,线程会被复用;否则会被销毁,任务会由新线程执行。

常见用法:
查看线程池当前过期时间

QThreadPool *pool = QThreadPool::globalInstance();
qDebug() << "线程过期超时设置:" << pool->expiryTimeout() << "毫秒";

示例:动态查看线程池设置

#include <QThreadPool>
#include <QDebug>void checkThreadExpiry() {QThreadPool *pool = QThreadPool::globalInstance();int timeout = pool->expiryTimeout();qDebug() << "当前线程空闲超时时间为:" << timeout << "毫秒";
}

默认值说明:
在这里插入图片描述
使用建议:
在这里插入图片描述
注意事项:

  • 不是任务超时控制! 而是线程空闲后多久自动销毁;
  • 如果想设置任务运行超时时间,请自行实现定时器或任务取消逻辑;
  • 该值仅影响线程资源生命周期,不影响任务调度本身。

2.4 int QThreadPool::maxThreadCount() const
功能说明:返回当前线程池最多能同时运行的线程数,即线程并发上限。

举例使用:
查看最大线程数

QThreadPool *pool = QThreadPool::globalInstance();
int maxThreads = pool->maxThreadCount();
qDebug() << "最大并发线程数为:" << maxThreads;

示例完整代码:

#include <QThreadPool>
#include <QDebug>void checkMaxThreads() {QThreadPool *pool = QThreadPool::globalInstance();qDebug() << "系统推荐线程数:" << QThread::idealThreadCount();qDebug() << "当前线程池最大线程数:" << pool->maxThreadCount();// 修改最大线程数pool->setMaxThreadCount(6);qDebug() << "新设置的线程数:" << pool->maxThreadCount();
}

注意事项:

  • maxThreadCount 并不限制任务数,而是限制同时运行的线程数;
  • 超过限制的任务将被排队等待空闲线程;
  • 合理设置 maxThreadCount 有助于控制 CPU 占用,避免过载;

2.5 void QThreadPool::releaseThread()
功能说明:手动减少线程池中当前正在使用的线程数量计数(active thread count)。它通常与 reserveThread() 配对使用,用于手动控制线程池中线程资源的分配与释放。

搭配使用函数:
在这里插入图片描述
这两个函数并不创建或销毁线程,而是修改线程池的线程调度计数。

使用场景:

  • 手动管理线程资源(例如,你希望在线程池外运行一个任务,但仍希望线程池认为资源被占用);
  • 结合线程池调度机制实现资源预留、动态控制;
  • 防止线程池同时执行过多重量级任务。

示例:手动预留和释放线程数

#include <QThreadPool>
#include <QDebug>void manualThreadReservationExample() {QThreadPool *pool = QThreadPool::globalInstance();qDebug() << "初始最大线程数:" << pool->maxThreadCount();qDebug() << "当前活动线程数:" << pool->activeThreadCount();// 预留两个线程名额pool->reserveThread();pool->reserveThread();qDebug() << "预留2个线程后,可用线程减少";// 此时任务提交将受到最大线程数 - 预留数量的限制// 执行完后释放线程名额pool->releaseThread();pool->releaseThread();qDebug() << "已释放预留线程,线程池恢复可用资源";
}

注意事项:

  • 不要调用 releaseThread() 多于 reserveThread() 次数,否则行为未定义;
  • 不影响正在运行的线程,仅影响调度器的内部计数;
  • 使用前确保了解线程池任务调度原理,避免死锁或资源错误判断;
  • 若使用不当可能会导致线程池任务无法调度或调度过多。

2.6 void QThreadPool::setExpiryTimeout(int expiryTimeout)
参数说明:expiryTimeout:以毫秒为单位,指定一个线程在空闲多久后将被销毁(退出)。如果设置为 -1,表示线程永远不会因空闲而销毁。默认值是 30000 毫秒(30 秒)。

作用:这个函数用于优化线程资源使用,当线程池中的线程空闲超过指定时间,它们将被自动销毁,从而释放系统资源。

使用示例:

#include <QCoreApplication>
#include <QThreadPool>
#include <QRunnable>
#include <QDebug>class MyTask : public QRunnable {
public:void run() override {qDebug() << "Task running on thread:" << QThread::currentThread();QThread::sleep(1);}
};int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);QThreadPool* pool = QThreadPool::globalInstance();// 设置空闲线程在 5 秒后自动销毁pool->setExpiryTimeout(5000);// 提交一个任务pool->start(new MyTask());// 等待所有任务完成pool->waitForDone();qDebug() << "All tasks done. Wait to see if thread exits.";// 等待超过 5 秒,以观察线程是否被销毁QThread::sleep(7);return 0;
}

2.7 void QThreadPool::setMaxThreadCount(int maxThreadCount)
参数说明:maxThreadCount:线程池中允许同时活动的线程最大数量(非等待任务数量)。必须大于 0,否则不会生效。默认值通常为系统核心数:QThread::idealThreadCount()。

作用说明:
setMaxThreadCount() 控制了线程池的并发程度:

  • 如果你提交了很多任务,线程池也只会最多并发执行 maxThreadCount 个任务,其他任务会排队。
  • 增加 maxThreadCount 可以提升并发处理能力,但也会增加线程上下文切换、CPU 竞争。

使用示例:

#include <QCoreApplication>
#include <QThreadPool>
#include <QRunnable>
#include <QDebug>class MyTask : public QRunnable {
public:void run() override {qDebug() << "Running task on thread:" << QThread::currentThread();QThread::sleep(2); // 模拟耗时任务}
};int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);QThreadPool* pool = QThreadPool::globalInstance();// 设置最大线程数为 2(并发数限制为 2)pool->setMaxThreadCount(2);qDebug() << "Max thread count:" << pool->maxThreadCount();// 提交 5 个任务for (int i = 0; i < 5; ++i) {pool->start(new MyTask());}pool->waitForDone();qDebug() << "All tasks completed.";return 0;
}

输出分析(示意):

Max thread count: 2
Running task on thread: 0x7ff...
Running task on thread: 0x7ff...
... 2 秒后 ...
Running task on thread: 0x7ff...
Running task on thread: 0x7ff...
...2...
Running task on thread: 0x7ff...

可以看到虽然提交了 5 个任务,但同时运行的最多只有 2 个线程。

2.8 void QThreadPool::setStackSize(uint stackSize)
参数说明:

  • stackSize:单位是字节(byte),表示线程的栈大小。
  • 通常应设置为足够执行任务所需的内存空间。
  • 如果设置为 0,表示使用系统默认栈大小。
  • 如果设置值太小,可能会导致线程运行时栈溢出(stack overflow)。
  • 设置过大,则会增加内存占用。

作用与适用场景:
在这里插入图片描述
注意:不是所有平台都支持修改线程栈大小,在某些平台(如 Windows)上无效或有限制。

使用示例:

#include <QCoreApplication>
#include <QThreadPool>
#include <QRunnable>
#include <QDebug>class MyTask : public QRunnable {
public:void run() override {qDebug() << "Task running. Thread:" << QThread::currentThread();char largeArray[1024 * 512]; // 使用较大的局部变量,512 KBlargeArray[0] = 1; // 防止优化}
};int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);QThreadPool* pool = QThreadPool::globalInstance();// 设置每个线程栈大小为 2 MBpool->setStackSize(2 * 1024 * 1024);qDebug() << "Set thread stack size to 2MB";pool->start(new MyTask());pool->waitForDone();return 0;
}

注意事项:

  • 只对新创建的线程生效,对已存在的线程无效。
  • 与操作系统有关,某些系统可能会忽略此设置或限制最大栈大小。
  • 设置过小容易造成崩溃(stack overflow),尤其在递归或大数组情况下。
  • 大部分任务无需设置栈大小,仅在特殊需求下使用。

2.9 uint QThreadPool::stackSize() const
返回值:

  • 返回一个 uint(无符号整数),表示线程池中新创建线程的栈大小(单位:字节)。
  • 如果返回值为 0,表示使用系统默认的线程栈大小。

作用说明:查询你通过 setStackSize() 设置的栈大小配置值。它不会告诉你系统默认的实际栈大小,只会返回你自己设定的值或 0。

使用示例:

#include <QCoreApplication>
#include <QThreadPool>
#include <QDebug>int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);QThreadPool *pool = QThreadPool::globalInstance();// 设置栈大小为 1 MBpool->setStackSize(1024 * 1024);// 读取当前设置的栈大小uint size = pool->stackSize();qDebug() << "Current thread stack size:" << size << "bytes";return 0;
}

输出示例:

Current thread stack size: 1048576 bytes

如果你没有调用 setStackSize(),默认输出为:

Current thread stack size: 0 bytes

2.10 void QThreadPool::start(QRunnable *runnable, int priority = 0)
参数说明:

  • runnable:指向一个继承自 QRunnable 的任务对象指针。
  • priority:任务优先级(整型),默认值为 0。
    • 数值越大,优先级越高。
    • 是相对优先级,不代表线程调度的精确控制,仅用于线程池内部排序。
    • 通常范围在 -128 ~ 127(没有硬性限制,但这个区间最常用)。

使用示例:
示例:提交一个任务到线程池

#include <QCoreApplication>
#include <QThreadPool>
#include <QRunnable>
#include <QDebug>class MyTask : public QRunnable {
public:void run() override {qDebug() << "Running task in thread:" << QThread::currentThread();}
};int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);// 获取全局线程池QThreadPool* pool = QThreadPool::globalInstance();// 创建任务QRunnable* task = new MyTask();task->setAutoDelete(true); // 任务完成后自动释放内存// 提交任务,优先级为默认(0)pool->start(task);pool->waitForDone(); // 等待所有任务执行完毕return 0;
}

示例:带优先级任务

QRunnable* low = new MyTask();
QRunnable* high = new MyTask();low->setAutoDelete(true);
high->setAutoDelete(true);// 高优先级任务先执行
pool->start(high, 10);
pool->start(low, -5);

2.11 bool QThreadPool::tryStart(QRunnable *runnable)
参数说明:runnable:指向 QRunnable 子类的任务对象。

功能说明:用于尝试立即启动一个任务,如果线程池中当前有空闲线程可用,就立即执行,否则不执行任务。

返回值:

  • true:任务已被成功启动(线程池中有空闲线程)。
  • false:线程池中没有空闲线程,任务未启动,你需要手动处理(例如等待或丢弃)。

作用说明:
在这里插入图片描述
使用示例:

#include <QCoreApplication>
#include <QThreadPool>
#include <QRunnable>
#include <QDebug>class MyTask : public QRunnable {
public:void run() override {qDebug() << "Running task in thread:" << QThread::currentThread();QThread::sleep(2); // 模拟耗时任务}
};int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);QThreadPool *pool = QThreadPool::globalInstance();pool->setMaxThreadCount(2); // 最多两个并发线程// 启动两个任务,占满线程池pool->start(new MyTask());pool->start(new MyTask());// 第三个任务尝试用 tryStart 启动(可能失败)QRunnable *extra = new MyTask();extra->setAutoDelete(true);if (pool->tryStart(extra)) {qDebug() << "Extra task started.";} else {qDebug() << "No threads available — task not started.";delete extra; // 必须手动释放,否则内存泄漏}pool->waitForDone();return 0;
}

注意事项:
在这里插入图片描述
2.12 bool QThreadPool::tryTake(QRunnable *runnable)
参数说明:runnable:指向你先前提交(但尚未开始执行)的 QRunnable 任务对象。

返回值:

  • true:任务成功被从线程池队列中移除(即:尚未开始执行,已经成功取消)。
  • false:任务已经开始执行或不在队列中,无法移除。

作用说明:

  • 任务撤销:在任务还没开始前取消它。
  • 动态调整任务:根据程序逻辑变化取消一些不再需要的任务。

使用示例:

#include <QCoreApplication>
#include <QThreadPool>
#include <QRunnable>
#include <QDebug>
#include <QThread>class MyTask : public QRunnable {
public:void run() override {qDebug() << "Task running in thread:" << QThread::currentThread();QThread::sleep(2);}
};int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);QThreadPool* pool = QThreadPool::globalInstance();pool->setMaxThreadCount(1); // 限制只允许一个线程运行// 创建两个任务MyTask* task1 = new MyTask();task1->setAutoDelete(true);MyTask* task2 = new MyTask();task2->setAutoDelete(true);pool->start(task1); // 会立即执行(占用线程)pool->start(task2); // 会排队// 尝试移除 task2(注意它必须尚未运行)bool removed = pool->tryTake(task2);qDebug() << (removed ? "Task2 was removed from queue" : "Task2 could not be removed");pool->waitForDone();return 0;
}

输出示例:

Task running in thread: 0x7f8c4bc0
Task2 was removed from queue

2.13 bool QThreadPool::waitForDone(int msecs = -1)
参数说明:

  • msecs:等待的最长时间(单位:毫秒)。
    • 默认值 -1 表示无限等待,直到所有任务执行完毕为止。
    • 设为具体时间值(如 5000)表示最多等待 5 秒。

返回值:

  • true:所有任务已完成。
  • false:等待超时,还有任务未完成。

作用说明:这个函数主要用于在程序需要确保所有任务执行完毕再继续下一步操作时使用。

使用示例:
示例:无限等待所有任务执行完毕

#include <QCoreApplication>
#include <QThreadPool>
#include <QRunnable>
#include <QDebug>
#include <QThread>class MyTask : public QRunnable {
public:void run() override {qDebug() << "Task started in thread:" << QThread::currentThread();QThread::sleep(2); // 模拟耗时任务qDebug() << "Task finished";}
};int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);QThreadPool *pool = QThreadPool::globalInstance();for (int i = 0; i < 3; ++i) {MyTask *task = new MyTask();task->setAutoDelete(true);pool->start(task);}qDebug() << "Waiting for tasks to finish...";pool->waitForDone();  // 等待所有任务完成qDebug() << "All tasks completed.";return 0;
}

示例:最多等待 3 秒

bool success = pool->waitForDone(3000); // 最多等待 3000ms
if (success) {qDebug() << "Tasks finished in time.";
} else {qDebug() << "Timeout! Tasks still running.";
}

三、完整示例

示例功能:

  • 使用 QThreadPool 提交多个任务;
  • 每个任务继承自 QRunnable 并在子线程中执行;
  • 控制台打印线程运行情况;
  • 可自由设置线程池线程数。
#include <QCoreApplication>
#include <QThreadPool>
#include <QRunnable>
#include <QThread>
#include <QDebug>// 自定义任务类,继承 QRunnable
class MyTask : public QRunnable {
public:MyTask(int id) : taskId(id) {setAutoDelete(true);  // 任务执行后自动释放内存}void run() override {qDebug() << "任务开始 ID:" << taskId<< "在线程:" << QThread::currentThread();QThread::sleep(2); // 模拟耗时操作qDebug() << "任务完成 ID:" << taskId;}private:int taskId;
};int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);QThreadPool *pool = QThreadPool::globalInstance();// 设置最大线程数(可选)pool->setMaxThreadCount(4);qDebug() << "线程池最大线程数:" << pool->maxThreadCount();// 提交多个任务for (int i = 0; i < 8; ++i) {MyTask *task = new MyTask(i);pool->start(task);}// 等待所有任务完成pool->waitForDone();qDebug() << "所有任务已完成";return 0;
}

输出结果:

线程池最大线程数: 4
任务开始 ID: 0 在线程: QThread(0x2e436e0, name = "Thread (pooled)")
任务开始 ID: 1 在线程: QThread(0x2e43710, name = "Thread (pooled)")
任务开始 ID: 2 在线程: QThread(0x2e43b90, name = "Thread (pooled)")
任务开始 ID: 3 在线程: QThread(0x2e43aa0, name = "Thread (pooled)")
任务完成 ID: 2
任务完成 ID: 3
任务完成 ID: 0
任务完成 ID: 1
任务开始 ID: 4 在线程: QThread(0x2e43b90, name = "Thread (pooled)")
任务开始 ID: 5 在线程: QThread(0x2e43aa0, name = "Thread (pooled)")
任务开始 ID: 6 在线程: QThread(0x2e436e0, name = "Thread (pooled)")
任务开始 ID: 7 在线程: QThread(0x2e43710, name = "Thread (pooled)")
任务完成 ID: 4
任务完成 ID: 6
任务完成 ID: 7
任务完成 ID: 5
所有任务已完成

关键知识点总结
在这里插入图片描述


http://www.hkcw.cn/article/bEAGIFuagA.shtml

相关文章

蚂蚁感冒--思维

1.相遇后不用考虑转头&#xff0c;继续走就可以 2.思维&#xff0c;不只是傻傻的模拟&#xff0c;要总结出规律&#xff0c;什么情况一定可以感染&#xff0c;然后感染之后再怎么这么样 P8611 [蓝桥杯 2014 省 AB] 蚂蚁感冒 - 洛谷 #include<bits/stdc.h> using names…

non-autoregressive sequence generation

非自回归non-autoregressive 传统rnn是autoregressive,而且encode和decode都是根据上一个input/output,这样花费的时间就和句子长度成正比 transformer的输入是并行的,但是decode阶段还是autoregressive 单纯把影像当成 NM 个独立像素去拟合&#xff0c;会缺乏像素之间的依赖…

实验设计与分析(第6版,Montgomery著,傅珏生译) 第10章拟合回归模型10.9节思考题10.1 R语言解题

本文是实验设计与分析&#xff08;第6版&#xff0c;Montgomery著&#xff0c;傅珏生译) 第10章拟合回归模型10.9节思考题10.1 R语言解题。主要涉及线性回归、回归的显著性、回归系数的置信区间。 vial <- seq(1, 10, 1) Viscosity <- c(160,171,175,182,184,181,188,19…

如何选择最高效的沟通方式?

日常沟通主要分为文字、语音和面对面三种形式&#xff0c;选择何种方式需根据沟通内容的复杂程度、决策难度及互动需求综合判断。 当沟通内容简单明确、以信息传递为主或涉及基础决策时&#xff0c;文字或语音是更高效的选择。这类方式不仅能降低时间成本&#xff0c;还能避免…

VueScan:全能扫描,高清输出

在数字化办公和图像处理的领域&#xff0c;扫描仪扮演着不可或缺的角色。无论是文档的数字化存档、照片的高清复制&#xff0c;还是创意项目的素材采集&#xff0c;一款性能卓越、操作便捷的扫描软件能大幅提升工作效率和成果质量。VueScan正是这样一款集多功能于一身的扫描仪软…

【Hot 100】279. 完全平方数

目录 引言完全平方数我的解题dp总结 &#x1f64b;‍♂️ 作者&#xff1a;海码007&#x1f4dc; 专栏&#xff1a;算法专栏&#x1f4a5; 标题&#xff1a;【Hot 100】279. 完全平方数❣️ 寄语&#xff1a;书到用时方恨少&#xff0c;事非经过不知难&#xff01; 引言 今天又…

Alita:通过 MCP 实现自主进化的通用 AI 代理

Alita 是一个创新的通用 AI 代理&#xff0c;采用极简主义设计哲学&#xff0c;强调 minimal predefinition&#xff08;最小预定义&#xff09;和 maximal self-evolution&#xff08;最大自主进化&#xff09;。通过利用 Model Context Protocols (MCPs)&#xff0c;Alita 能…

关于物联网的基础知识(二)——物联网体系结构分层

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///计算机爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于物联网的基础知识&#xff08;二&a…

大语言模型评测体系全解析(上篇):基础框架与综合评测平台

文章目录 一、评测体系的历史演进与技术底座&#xff08;一&#xff09;发展历程&#xff1a;从单任务到全维度评测1. 2018年前&#xff1a;单数据集时代的萌芽2. 2019-2023年&#xff1a;多任务基准的爆发式增长3. 2024年至今&#xff1a;动态化、场景化、多模态体系成型关键节…

SpringAI系列 - MCP篇(三) - MCP Client Boot Starter

目录 一、Spring AI Mcp集成二、Spring AI MCP Client Stater三、spring-ai-starter-mcp-client-webflux集成示例3.1 maven依赖3.2 配置说明3.3 集成Tools四、通过SSE连接MCP Server五、通过STDIO连接MCP Server六、通过JSON文件配置STDIO连接一、Spring AI Mcp集成 Spring AI…

MyBatis 一级缓存与二级缓存

一、缓存概述 MyBatis 提供两级缓存机制提升查询性能&#xff1a; 一级缓存&#xff1a;SqlSession 级别&#xff0c;默认开启 二级缓存&#xff1a;Mapper 级别&#xff0c;需手动开启 两者协同工作&#xff0c;形成查询数据优先级&#xff1a;二级缓存 → 一级缓存 → 数据…

008房屋租赁系统技术揭秘:构建智能租赁服务生态

房屋租赁系统技术揭秘&#xff1a;构建智能租赁服务生态 在房地产租赁市场日益活跃的当下&#xff0c;房屋租赁系统成为连接房东与租客的重要数字化桥梁。该系统集成用户管理、房屋信息等多个核心模块&#xff0c;面向管理员、房东和用户三类角色&#xff0c;通过前台展示与后…

HTTP协议完全指南:从请求响应到HTTPS安全机制

文章目录 一、HTTP协议中的基本概念1.HTTP协议介绍&#xff08;1&#xff09;协议&#xff08;2&#xff09;传输&#xff08;3&#xff09;超文本 2.统一资源定位符&#xff08;URL&#xff09; 二、HTTP协议中的请求和响应1.HTTP客户端请求消息&#xff08;1&#xff09;请求…

第11节 Node.js 模块系统

为了让Node.js的文件可以相互调用&#xff0c;Node.js提供了一个简单的模块系统。 模块是Node.js 应用程序的基本组成部分&#xff0c;文件和模块是一一对应的。换言之&#xff0c;一个 Node.js 文件就是一个模块&#xff0c;这个文件可能是JavaScript 代码、JSON 或者编译过的…

『uniapp』把接口的内容下载为txt本地保存 / 读取本地保存的txt文件内容(详细图文注释)

目录 预览效果思路分析downloadTxt 方法readTxt 方法 完整代码总结 欢迎关注 『uniapp』 专栏&#xff0c;持续更新中 欢迎关注 『uniapp』 专栏&#xff0c;持续更新中 预览效果 思路分析 downloadTxt 方法 该方法主要完成两个任务&#xff1a; 下载 txt 文件&#xff1a;通…

XCTF-web-ics-05

看一下有什么 只有/index.php 模糊测试得到一个page ┌──(kali㉿kali)-[~] └─$ ffuf -u "http://223.112.5.141:52073/index.php?FUZZFUZZ" -w /usr/share/wordlists/rockyou.txt -fc 403 -c -fs 2305 -s page尝试用php伪协议读取源码?pagephp://filter/readc…

Redis线程模型

前面的文章介绍了Redis的底层数据结构&#xff0c;这篇文章来介绍一下Redis的线程模型。 Redis为什么选择单线程&#xff1f; 官方的回答是这样的&#xff0c;对于Redis来说&#xff0c;CPU通常不会成为瓶颈&#xff0c;因为大多数的请求不会是CPU密集型的&#xff0c;而是IO密…

工厂方法模式深度解析:从原理到应用实战

作者简介 我是摘星&#xff0c;一名全栈开发者&#xff0c;专注 Java后端开发、AI工程化 与 云计算架构 领域&#xff0c;擅长Python技术栈。热衷于探索前沿技术&#xff0c;包括大模型应用、云原生解决方案及自动化工具开发。日常深耕技术实践&#xff0c;乐于分享实战经验与…

STM32入门教程——按键控制LED光敏传感器控制蜂鸣器

前言 本教材基于B站江协科技课程整理&#xff0c;适合有C语言基础、刚接触STM32的新手。它梳理了STM32核心知识点&#xff0c;帮助大家把C语言知识应用到STM32开发中&#xff0c;更高效地开启STM32学习之旅。 目录 前言 一、硬件接线与模块化编程概述 二、LED 驱动模块开发…

K8s基础一

Kubernetes 架构 Kubernetes 背后的架构概念。 Kubernetes 集群由一个控制平面和一组用于运行容器化应用的工作机器组成&#xff0c; 这些工作机器称作节点&#xff08;Node&#xff09;。每个集群至少需要一个工作节点来运行 Pod。 工作节点托管着组成应用负载的 Pod。控制平…