QTableWidget 中insertRow(0)(头插)和 insertRow(rowCount())(尾插)的性能差异
一、目的
在 Qt 的 QTableWidget 中,insertRow(0) (头插)和 insertRow(rowCount())(尾插)在性能上存在显著差异。
二、QAbstractItemModel:: insertRows 原文解释
QAbstractItemModel Class | Qt Core 5.15.18
![![[QAbstractItemModel-insertRows.png]]](https://i-blog.csdnimg.cn/direct/6e55a91b27b0444d89be40ca000410ef.png)
AI 解释
QAbstractItemModel:: insertRows 是 Qt 模型/视图框架中用于在模型中插入行的一个虚函数。以下是对该函数的详细解释,包括其功能、参数、返回值以及如何正确实现自定义模型中的插入操作。
函数声明
[virtual] bool QAbstractItemModel::insertRows(int row, int count, const QModelIndex &parent = QModelIndex())
功能概述
insertRows 函数用于在模型中指定位置插入一行或多行数据。具体来说,它会在给定的 row 位置之前插入 count 行新数据。这些新行将成为由 parent 模型索引表示的父项的子项。
参数说明
-
int row
指定插入行的位置。如果row为0,新行将被插入到父项的最前面;如果row等于rowCount(parent),新行将被追加到父项的最后面。 -
int count
要插入的行数。可以一次性插入多行数据。 -
const QModelIndex &parent = QModelIndex()
表示插入行的父索引。如果parent是无效索引(默认值),则插入的行将成为顶级行(即没有父项)。否则,新行将作为parent所表示的父项的子项插入。
返回值
-
bool
返回true表示插入操作成功;返回false表示插入操作失败。
注意事项
- 基类实现
QAbstractItemModel的基类实现是空的,直接调用会返回false。因此,如果你的自定义模型需要支持插入行的操作,必须重写(reimplement)此函数。 - 通知机制
在实际插入数据之前和之后,必须调用beginInsertRows和endInsertRows函数。这两个函数用于通知视图和其他相关组件模型数据的变化,以确保界面能够正确更新。 - 实现逻辑
当重写insertRows时,除了调用beginInsertRows和endInsertRows来通知变化外,还需要在内部数据结构中实际插入新的数据行。
示例代码
以下是一个简单的自定义模型中重写 insertRows 的示例:
#include <QAbstractItemModel>
#include <QModelIndex>
#include <QVariant>
#include <QList>class MyModel : public QAbstractItemModel {Q_OBJECTpublic:// 构造函数和其他必要的成员函数...// 重写 insertRows 函数bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) override {// 开始插入操作的通知beginInsertRows(parent, row, row + count - 1);// 在内部数据结构中插入新行if (!parent.isValid()) {// 插入顶级行for (int i = 0; i < count; ++i) {m_data.insert(row, QVariant()); // 假设 m_data 是 QList<QVariant>}} else {// 插入子行(假设父项有子项列表)MyItem *parentItem = static_cast<MyItem*>(parent.internalPointer());if (parentItem) {parentItem->appendChildItems(count); // 假设有相应的方法添加子项}}// 结束插入操作的通知endInsertRows();return true; // 插入成功}// 其他必要的虚函数实现...private:QList<QVariant> m_data; // 示例数据结构,实际应用中可能更复杂
};
详细解释
-
调用
beginInsertRowsbeginInsertRows(parent, row, row + count - 1);这个函数通知所有连接到模型的视图,即将在
parent父索引下的row到row + count - 1位置插入新行。这使视图能够预先调整其布局和缓冲区,以适应即将到来的数据变化。 -
修改内部数据结构
根据parent是否有效,决定是插入顶级行还是子行:- 顶级行:直接在
m_data列表的指定位置插入新数据。 - 子行:通过
parent获取对应的父项对象,并调用相应的方法在父项下插入新的子项。
- 顶级行:直接在
-
调用
endInsertRowsendInsertRows();这个函数通知视图插入操作已完成,视图可以更新显示新的数据行。
-
返回值
返回true表示插入操作成功。如果插入过程中出现错误,可以返回false,但通常需要提供适当的错误处理机制。
使用场景
- 动态添加数据:当用户通过界面按钮或其他方式请求添加新行时,模型通过
insertRows插入新数据。 - 批量插入:一次性插入多行数据,提高效率。
- 层级结构:在树形结构模型中,为特定父项插入子行。
性能考虑
- 通知开销:频繁调用
beginInsertRows和endInsertRows可能导致性能下降。因此,应尽量批量插入数据,而不是逐行插入。 - 数据结构的效率:确保内部数据结构支持高效的插入操作。例如,使用链表可以快速在头部插入,而动态数组在尾部插入更高效。
总结
QAbstractItemModel::insertRows 是实现自定义模型时用于插入新行的关键函数。通过正确重写此函数,并结合 beginInsertRows 和 endInsertRows 的通知机制,可以确保模型数据的动态变化能够正确反映在关联的视图上,同时保持良好的性能和用户体验。
三、QTableWidget::insertRow(int row) 源码
路径
- Qt\5.15.2\Src\qtbase\src\widgets\itemviews\qtablewidget. cpp
- Qt\5.15.2\Src\qtbase\src\widgets\itemviews\qtablewidget_p.h
代码解析
void QTableWidget::insertRow(int row)
{Q_D(QTableWidget);d->tableModel()->insertRows(row);
}bool QTableModel::insertRows(int row, int count, const QModelIndex &)
{if (count < 1 || row < 0 || row > verticalHeaderItems.count())return false;beginInsertRows(QModelIndex(), row, row + count - 1);int rc = verticalHeaderItems.count();int cc = horizontalHeaderItems.count();verticalHeaderItems.insert(row, count, 0);if (rc == 0)tableItems.resize(cc * count);elsetableItems.insert(tableIndex(row, 0), cc * count, 0);endInsertRows();return true;
}class QTableModel : public QAbstractTableModel
{Q_OBJECTfriend class QTableWidget;.....
private:const QTableWidgetItem *prototype;QVector<QTableWidgetItem*> tableItems;QVector<QTableWidgetItem*> verticalHeaderItems;QVector<QTableWidgetItem*> horizontalHeaderItems;// A cache must be mutable if get-functions should have const modifiersmutable QModelIndexList cachedIndexes; };
从这段代码可以看出,QTableWidget 的插入行操作实际上是通过其内部的 QTableModel 来实现的,具体步骤包括:
- 插入表头项:
verticalHeaderItems.insert(row, count, 0); - 插入表格数据项:
- 如果当前表格没有行 (
rc == 0),则直接调整tableItems的大小。 - 否则,在指定位置插入新的数据项,
tableItems.insert(tableIndex(row, 0), cc * count, 0);
- 如果当前表格没有行 (
性能差异分析
1. 性能差异的核心原因
头插 (insertRow(0))
- 表头项操作:
verticalHeaderItems.insert(row, count, 0)在QVector头部插入元素,需要将后续所有元素向后移动,时间复杂度为 O (n)(n 为当前行数)。 - 表格数据操作:
tableItems.insert(tableIndex(row, 0), cc * count, 0)在数据数组头部插入新元素,同样需要移动后续所有数据,时间复杂度为 O (n * m)(m 为列数)。 - 视图更新:
触发beginInsertRows和endInsertRows,通知视图重新计算所有行的位置,导致界面重绘开销较大。
尾插 (insertRow(rowCount()))
- 表头项操作:
在QVector尾部追加元素,时间复杂度为 O (1)(假设预分配了足够内存)。 - 表格数据操作:
- 若表格为空,通过
tableItems.resize(cc * count)初始化内存(O (1))。 - 若表格非空,直接追加到
QVector末尾(O (1))。
- 若表格为空,通过
- 视图更新:
视图仅需扩展显示区域,渲染开销更低。
2. 插入操作的时间复杂度
- 尾插 (
insertRow(rowCount())):- 表头项插入:在
QVector的末尾插入元素,时间复杂度为 O(1)。 - 表项数据插入:如果表格为空,仅需调整大小;否则,由于是在末尾插入,
QVector::insert在有预留空间的情况下也是 O(1)。但如果有重新分配内存的需求,可能会涉及到 O(n) 的复制操作,但这种情况在尾部插入时较少发生。
- 表头项插入:在
- 头插 (
insertRow(0)):- 表头项插入:在
QVector的开头插入元素,需要移动所有现有元素,时间复杂度为 O(n)。 - 表项数据插入:同样,在开头插入需要移动所有现有的数据项,时间复杂度为 O(n)。如果表格较大,这种移动操作的开销会显著增加。
- 表头项插入:在
3. 实际性能影响
- 数据量较小:
- 当表格中的行数较少(例如几十行)时,头插和尾插的性能差异可能不明显,用户几乎感觉不到延迟。
- 数据量较大:
- 当表格包含数千行甚至更多行时,头插操作由于需要频繁移动大量元素,会导致明显的性能下降,甚至可能造成界面卡顿或响应延迟。
- 尾插操作由于主要在末尾添加元素,性能相对稳定,几乎不受插入次数的影响。
4. 内存与缓存的影响
- 内存重新分配:
QVector在插入元素时,如果当前容量不足以容纳新元素,会进行内存重新分配和元素复制。头插操作由于频繁移动元素,可能更频繁地触发内存重新分配,增加开销。
- 缓存局部性:
- 尾插操作更有利于 CPU 缓存的利用,因为新元素通常被添加到内存的连续区域。而头插操作打乱了数据的连续性,导致缓存命中率降低,进一步影响性能。
5. 实际性能对比
| 操作类型 | 时间复杂度 | 内存移动次数 | 适用场景 | 性能影响 |
|---|---|---|---|---|
| 头插 | O(n) | 高(n 次移动) | 按倒序插入少量数据 | 高(避免频繁使用) |
| 尾插 | O(1) | 低(尾部追加) | 常规数据追加、大规模插入 | 低(推荐优先使用) |
- 小数据量场景(如数十行):两者差异可忽略。
- 大数据量场景(如数万行): - 头插单行耗时可能是尾插的 10 倍以上(因需移动全部数据)。 - 尾插性能稳定,适合高频插入操作。
四、 示例测试
以下是一个使用 QElapsedTimer 和 QTableWidget 测试 insertRow(0)(头插)和 insertRow(rowCount())(尾插)性能差异的完整示例代码。代码通过批量插入数据并测量时间,直观展示两者的性能差距:
#include <QApplication>
#include <QTableWidget>
#include <QTableWidgetItem>
#include <QElapsedTimer>
#include <QTimer>
#include <QDebug>// 测试函数:插入指定行数到表格的头部或尾部
void testInsertPerformance(QTableWidget* table, int rowCount, const QString& testName) {table->clearContents();table->setRowCount(0);// 禁用视图更新以提高测试准确性table->setUpdatesEnabled(false);QElapsedTimer timer;timer.start();for (int i = 0; i < rowCount; ++i) {int row = (testName == "Head Insert") ? 0 : table->rowCount();table->insertRow(row);table->setItem(row, 0, new QTableWidgetItem(QString("Name %1").arg(i)));table->setItem(row, 1, new QTableWidgetItem(QString::number(i)));table->setItem(row, 2, new QTableWidgetItem(QString("City %1").arg(i % 10)));}auto elapsed_ms = timer.elapsed();table->setUpdatesEnabled(true); // 恢复视图更新qDebug() << testName << "Performance:";qDebug() << " Time elapsed:" << elapsed_ms << "ms";qDebug() << " Time elapsed:" << elapsed_ms << "ms";qDebug() << " Memory used:" << table->sizeHint().height() * sizeof(QTableWidgetItem*) / 1024.<< "KB";qDebug() << " Memory used:" << table->sizeHint().width() * sizeof(QTableWidgetItem*) / 1024.<< "KB";
}int main(int argc, char* argv[]) {QApplication a(argc, argv);// 创建测试表格(3列)QTableWidget table;table.setColumnCount(3);table.setHorizontalHeaderLabels({ "Name", "Age", "City" });table.resize(600, 400);table.show();
#if 1// 测试头插性能(插入100000行)testInsertPerformance(&table, 100000, "Head Insert");// 等待用户操作后测试尾插性能QTimer::singleShot(2000, [&]() {testInsertPerformance(&table, 100000, "Tail Insert");});
#else//测试尾插性能testInsertPerformance(&table, 100000, "Tail Insert");// 等待用户操作后测试头插性能QTimer::singleShot(2000, [&]() {testInsertPerformance(&table, 100000, "Head Insert");});
#endifreturn a.exec();
}
代码解析与测试结果
1. 核心逻辑
- 禁用视图更新:通过
setUpdatesEnabled(false)暂停界面刷新,避免渲染开销干扰时间测量。 - 批量插入数据:循环插入指定行数,每行包含姓名、年龄、城市三列数据。
- 时间测量:使用
QElapsedTimer记录插入操作的耗时。 - 内存估算:通过
sizeHint().height()估算表格占用的内存(粗略计算)。
2. 测试结果示例
![![[100000performance.png]]](https://i-blog.csdnimg.cn/direct/b671f9dc975e4f7d84e61e3acc0a3136.png)
| 操作类型 | 插入行数 | 耗时(ms) | 内存占用(KB) | |
|---|---|---|---|---|
| 头插 | 100,000 | 9,224 | 1.5 | |
| 尾插 | 100,000 | 2509 | 1.5 | |
注:实际结果可能因硬件和 Qt 版本略有差异,但头插耗时通常比尾插高 。
性能差异原因
-
头插 (
insertRow(0)):- 数据移动:
QVector在头部插入元素需移动后续所有元素,时间复杂度为 O(n)。 - 内存重新分配:频繁插入导致内存多次重新分配,增加开销。
- 数据移动:
-
尾插 (
insertRow(rowCount())):- 尾部追加:
QVector在尾部插入元素时间复杂度为 O(1)(预分配内存时)。 - 内存连续性:数据连续存储,缓存命中率高。
- 尾部追加:
优化建议
- 预分配内存:若已知数据量,提前调用
table->setRowCount(rowCount)预分配内存。 - 改用自定义模型:对超大数据集,使用
QAbstractTableModel替代QTableWidget,通过虚拟化技术减少内存占用。
五、 优化建议
基于上述分析,以下是一些优化建议:
-
优先使用尾插:
- 如果业务逻辑允许,尽量使用
insertRow(rowCount())进行尾插操作,以获得更好的性能表现。
- 如果业务逻辑允许,尽量使用
-
批量插入:
- 如果需要插入多行,尽量一次性批量插入,而不是逐行插入。例如,先收集所有需要插入的数据,然后调用一次
setRowCount。
// 示例:批量插入多行 tableWidget->setRowCount(10000); for (int i = 0; i < 10000; ++i) {// 填充数据 } - 如果需要插入多行,尽量一次性批量插入,而不是逐行插入。例如,先收集所有需要插入的数据,然后调用一次
-
使用模型/视图架构:
- 如果需要频繁进行插入、删除等操作,考虑直接使用
QAbstractTableModel或其子类QStandardItemModel,而不是QTableWidget。QAbstractTableModel提供了更高的灵活性和性能优化空间,尤其是在处理大规模数据时。 - 对于超大数据集,推荐使用
QTableView+ 自定义QAbstractTableModel/QStandardItemModel,通过虚拟化技术减少内存和渲染开销。例如:
class CustomTableModel : public QAbstractTableModel {// 实现 data()、rowCount()、columnCount() 等虚函数 }; QTableView *tableView = new QTableView; tableView->setModel(new CustomTableModel); // 或者 tableView->setModel(new QStandardItemModel); - 如果需要频繁进行插入、删除等操作,考虑直接使用
-
延迟更新:
- 若必须头插,可先禁用视图更新(
setUpdatesEnabled(false)),插入多行后再统一刷新界面:
tableWidget->setUpdatesEnabled(false); for (int i = 0; i < 100; ++i) {tableWidget->insertRow(0); // 批量头插 } tableWidget->setUpdatesEnabled(true);- 在进行大量插入操作前,可以暂时禁用视图的更新,操作完成后再恢复。这可以通过
setUpdatesEnabled(false)和setUpdatesEnabled(true)实现,但需要注意处理好数据的一致性。
tableWidget->setUpdatesEnabled(false); // 执行批量插入操作 tableWidget->setUpdatesEnabled(true); - 若必须头插,可先禁用视图更新(
-
懒加载技术:
- 仅在可见区域加载数据,结合滚动事件动态插入行(参考 QT 懒加载技术 的
UpdateAlarmList实现):
void AlarmCenter::wheelEvent(QWheelEvent *event) {// 根据滚动条位置动态加载数据int visibleRows = tableViewHeight / rowHeight;int startRow = currentRow - visibleRows / 2;UpdateAlarmList(startRow, visibleRows); } - 仅在可见区域加载数据,结合滚动事件动态插入行(参考 QT 懒加载技术 的
-
性能对比总结:
| 指标 | 头插 | 尾插 |
|---|---|---|
| 时间复杂度 | O (n)(数据移动) | O (1)(尾部追加) |
| 内存操作 | 高(频繁重新分配和复制) | 低(预分配或追加) |
| 界面渲染 | 高(全表重绘) | 低(仅扩展区域) |
| 适用场景 | 倒序插入少量数据 | 常规追加、大规模插入 |
总结
- 头插 (
insertRow(0)):- 性能较低,尤其是在数据量较大时,由于需要在开头插入元素,导致所有现有元素需要移动,时间复杂度为 O(n)。
- 尾插 (
insertRow(rowCount())):- 性能较高,在末尾插入元素通常为 O(1),即使有内存重新分配,也相对高效。
因此,在使用 QTableWidget::insertRow 时,尾插性能远优于头插,应优先考虑尾插操作,以获得更好的性能表现。如果业务逻辑确实需要频繁进行头插操作,建议重新评估设计,或者考虑使用更适合频繁插入删除操作的模型/视图架构(如 QAbstractTableModel)配合自定义的数据结构优化性能。
相关文章:
QTableWidget 中insertRow(0)(头插)和 insertRow(rowCount())(尾插)的性能差异
一、目的 在 Qt 的 QTableWidget 中,insertRow(0) (头插)和 insertRow(rowCount())(尾插)在性能上存在显著差异。 二、QAbstractItemModel:: insertRows 原文解释 QAbstractItemModel Class | Qt Core 5.15.18 AI 解…...
用nodejs连接mongodb数据库对标题和内容的全文本搜索,mogogdb对文档的全文本索引的设置以及用node-rs/jieba对标题和内容的分词
//首先我们要在Nodejs中安装 我们的分词库node-rs/jieba,这个分词不像jieba安装时会踩非常多的雷,而且一半的机率都是安装失败,node-rs/jieba比jieba库要快20-30%;安装分词库是为了更好达到搜索的效果 这个库直接npm install node-rs/jieba即…...
【万字总结】前端全方位性能优化指南(完结篇)——自适应优化系统、遗传算法调参、Service Worker智能降级方案
前言 自适应进化宣言 当监控网络精准定位病灶,真正的挑战浮出水面:系统能否像生物般自主进化? 五维感知——通过设备传感器实时捕获环境指纹(如地铁隧道弱光环境自动切换省电渲染) 基因调参——150个性能参数在遗传算…...
不绕弯地解决文件编码问题,锟斤拷烫烫烫
安装python对应库 pip install chardet 检测文件编码 import chardet# 检测文件编码 file_path rC:\Users\AA\Desktop\log.log # 这里放文件和文件绝对路径 with open(file_path, rb) as f:raw_data f.read(100000) # 读取前10000个字节result chardet.detect(raw_data)e…...
高密度任务下的挑战与破局:数字样机助力火箭发射提效提质
2025年4月1日12时,在酒泉卫星发射中心,长征二号丁运载火箭顺利升空,成功将一颗卫星互联网技术试验卫星送入预定轨道,发射任务圆满完成。这是长征二号丁火箭的第97次发射,也是长征系列火箭的第567次发射。 执行本次任务…...
QT Quick(C++)跨平台应用程序项目实战教程 6 — 弹出框
目录 1. Popup组件介绍 2. 使用 上一章内容完成了音乐播放器程序的基本界面框架设计。本小节完成一个简单的功能。单击该播放器顶部菜单栏的“关于”按钮,弹出该程序的相关版本信息。我们将使用Qt Quick的Popup组件来实现。 1. Popup组件介绍 Qt 中的 Popup 组件…...
【面试篇】Es
基础概念类 问题:请简要介绍 Elasticsearch 是什么,它的主要特点有哪些? 答案:Elasticsearch 是一个基于 Lucene 库的开源分布式搜索引擎和分析引擎。它能对海量数据进行实时搜索与分析,被广泛应用于日志分析、全文搜…...
KisFlow-Golang流式实时计算案例(四)-KisFlow在消息队列MQ中的应用
Golang框架实战-KisFlow流式计算框架专栏 Golang框架实战-KisFlow流式计算框架(1)-概述 Golang框架实战-KisFlow流式计算框架(2)-项目构建/基础模块-(上) Golang框架实战-KisFlow流式计算框架(3)-项目构建/基础模块-(下) Golang框架实战-KisFlow流式计算框架(4)-数据流 Golang框…...
leetcode:1582. 二进制矩阵中的特殊位置(python3解法)
难度:简单 给定一个 m x n 的二进制矩阵 mat,返回矩阵 mat 中特殊位置的数量。 如果位置 (i, j) 满足 mat[i][j] 1 并且行 i 与列 j 中的所有其他元素都是 0(行和列的下标从 0 开始计数),那么它被称为 特殊 位置。 示…...
大型语言模型的智能本质是什么
大型语言模型的智能本质是什么 基于海量数据的统计模式识别与生成系统,数据驱动的语言模拟系统 ,其价值在于高效处理文本任务(如写作、翻译、代码生成),而非真正的理解与创造 大型语言模型(如GPT-4、Claude等)的智能本质可概括为基于海量数据的统计模式识别与生成系统,…...
linux_sysctl_fs_file_nr监控项
在 Linux 系统中,/proc/sys/fs/file-nr 文件提供了当前系统打开文件句柄的信息。如果监控到文件打开数较高,可能会影响系统性能,甚至导致无法打开新文件(达到文件句柄上限)。以下是分析和解决该问题的步骤:…...
Cline – OpenRouter 排名第一的CLI 和 编辑器 的 AI 助手
Cline – OpenRouter 排名第一的CLI 和 编辑器 的 AI 助手,Cline 官网:https://github.com/cline/cline Star 37.8k ps,OpenRouter的网址是:OpenRouter ,这个排名第一,据我观察,是DeepSeek v3…...
Mock.js虚拟接口
Vue3中使用Mock.js虚拟接口数据 一、创建项目 pnpm创建vite的项目,通过 PNPM来简化依赖管理。若还没有安装 PNPM,可以通过 npm来安装: 安装 PNPM npm install -g pnpm//使用国内镜像加速pnpm add -g pnpmlatestpnpm config set registry http://regis…...
2025年嵌入式大厂春招高频面试真题及解析
以下是 2025 年嵌入式大厂春招高频面试真题及解析,结合真题分类和核心知识点整理: 一、C/C++编程基础 1.1 指针与内存 野指针的成因及避免方法(未初始化、释放后未置空) malloc与calloc的区别(后者自动初始化为0) 指针与数组的区别(内存分配方…...
LoRa模块通信距离优化:如何实现低功耗覆盖30公里无线传输要求
在物联网(IoT)快速发展的今天,LoRa(Long Range)技术作为一种基于扩频调制的远距离无线通信技术,因其远距离通信、低功耗和强抗干扰能力等优势,在农业监测、城市智能管理、环境监测等多个领域得到…...
OpenCV 从入门到精通(day_05)
1. 模板匹配 1.1 什么是模板匹配 模板匹配就是用模板图(通常是一个小图)在目标图像(通常是一个比模板图大的图片)中不断的滑动比较,通过某种比较方法来判断是否匹配成功。 1.2 匹配方法 rescv2.matchTemplate(image, …...
Linux操作系统与冯·诺依曼体系结构详解
一、冯诺依曼体系结构 1. 基本概念与历史背景 冯诺依曼体系结构是由数学家约翰冯诺依曼于1945年提出的计算机设计方案,也称为"存储程序计算机"。这一设计奠定了现代计算机的基础架构,至今仍是大多数计算机系统的核心设计理念。 2. 冯诺依曼体…...
OpenRouter开源的AI大模型路由工具,统一API调用
简介 OpenRouter是一个开源的路由工具,它可以绕过限制调用GPT、Claude等国外模型。以下是对它的详细介绍: 一、主要功能 OpenRouter专注于将用户请求智能路由到不同的AI模型,并提供统一的访问接口。它就像一个“路由器”,能…...
qt tcpsocket编程遇到的并发问题
1. 单个socket中接收消息的方法要使用局部变量而非全局,避免消息频发时产生脏数据 优化后的关键代码 recieveInfo() 方法通过返回内部处理后的 msg 进行传递if (data.indexOf("0103") -1) { 这里增加了判断, 对数据(非注册和心跳࿰…...
zabbix监控网站(nginx、redis、mysql)
目录 前提准备: zabbix-server主机配置: 1. 安装数据库 nginx主机配置: 1. 安装nginx redis主机配置: 1. 安装redis mysql主机配置: 1. 安装数据库 zabbix-server: 1. 安装zabbix 2. 编辑配置文…...
蓝桥杯冲刺
例题1:握手问题 方法1:数学推理(简单粗暴) 方法2:用代码实现方法1 #include<iostream> using namespace std; int main() {int result 0;for (int i 1; i < 49; i){for (int j i 1; j < 50; j){//第i个人与第j个…...
文心一言与 DeepSeek 的竞争分析:技术先发优势为何未能转化为市场主导地位?
目录 引言 第一部分:技术路径的差异——算法创新与工程优化的博弈 1.1 文心一言的技术积累与局限性 1.1.1 早期技术优势 1.1.2 技术瓶颈与局限性 1.2 DeepSeek 的技术突破 1.2.1 算法革命与工程创新 1.2.2 工程成本与效率优势 第二部分:生态策略…...
Spring Security(maven项目) 3.1.0
前言: 通过实践而发现真理,又通过实践而证实真理和发展真理。从感性认识而能动地发展到理性认识,又从理性认识而能动地指导革命实践,改造主观世界和客观世界。实践、认识、再实践、再认识,这种形式,循环往…...
合并两个有序数组(Java实现)
给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。 请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。 注意:最终,合并后数组…...
Tree - Shaking
Vue 3 的 Tree - Shaking 技术详解 Tree - Shaking 是一种在打包时移除未使用代码的优化技术,在 Vue 3 中,Tree - Shaking 发挥了重要作用,有效减少了打包后的代码体积,提高了应用的加载性能。以下是对 Vue 3 中 Tree - Shaking …...
C# 从代码创建选型卡+表格
private int tabNum 1; private int sensorNum 5; private void InitializeUI() {// 创建右侧容器面板Panel rightPanel new Panel{Dock DockStyle.Right,Width 300,BackColor SystemColors.ControlDark,Parent this};// 根据防区数量创建内容if (tabNum &g…...
OpenCV 从入门到精通(day_02)
1. 边缘填充 为什么要填充边缘呢?我们以下图为例: 可以看到,左图在逆时针旋转45度之后原图的四个顶点在右图中已经看不到了,同时,右图的四个顶点区域其实是什么都没有的,因此我们需要对空出来的区域进行一个…...
VTK的两种显示刷新方式
在类中先声明vtk的显示对象 vtkRenderer out_render; vtkVertexGlyphFilter glyphFilter; vtkPolyDataMapper mapper; // 新建制图器 vtkActor actor; // 新建角色 然后在init中先初始化一下: out_rend…...
Ceph异地数据同步之-RBD异地同步复制(上)
#作者:闫乾苓 文章目录 前言基于快照的模式(Snapshot-based Mode)工作原理单向同步配置步骤单向同步复制测试双向同步配置步骤双向同步复制测试 前言 Ceph的RBD(RADOS Block Device)支持在两个Ceph集群之间进行异步镜…...
【C++】STL库_stack_queue 的模拟实现
栈(Stack)、队列(Queue)是C STL中的经典容器适配器 容器适配器特性 不是独立容器,依赖底层容器(deque/vector/list)通过限制基础容器接口实现特定访问模式不支持迭代器操作(无法遍历…...
