深入浅出 Qt 中 QListView 的设计思想,并掌握大规模、高性能列表的实现方法

在大规模列表控件的显示需求中,必须解决2个问题才能获得较好的性能:

  1. 第一就是数据存在哪里, 避免出现数据的副本。
  2. 第二就是如何展示Item,如何复用或避免创建大量的Item控件。

在QListView体系里,QAbstractListModel解决的是“数据存哪”,解决的是第一个问题,而QAbstractItemDelegate解决的是数据“如何展示”,解决的是第二个问题。

因此,在大规模列表的编写代码中,高效的数据存储和高效的数据UI展示,需要用到这两个类。接下来,我们通过三个例子,循序渐进地介绍QListView,使读者掌握QListView的使用技巧和设计思想。

示例 1: 使用 QListWidget 的基本用法

QListWidget 是一个方便的控件,它内部管理了一个项目列表,并提供了一些简单的接口来添加、删除和修改这些项目。但没有对数据存储和数据展示进行过多的优化,这种方式适合于简单的应用场景,其中列表的大小不会很大,因为每个项目都会被存储为一个 QListWidgetItem 对象。

#include <QApplication>
#include <QListWidget>int main(int argc, char *argv[]) {QApplication app(argc, argv);    QListWidget* listWidget = new QListWidget;for (int i = 0; i < 100; ++i) {listWidget->addItem(QString("项目 %1").arg(i));}listWidget->show();    return app.exec();
}

尽管这种方式使用起来非常简单,但它并不适合处理大量数据。因为 QListWidget 会为每个项目创建一个 QListWidgetItem 对象,这将导致大量的内存消耗。

示例 2: 使用 QListView 和 QAbstractItemDelegate(解决数据存哪的问题)

在这个示例中,我们将直接从 QAbstractListModel 派生一个Model类,而不是使用 addItem构造大量的ItemData。这样,我们就无需存储这些数据。这个方法在处理具有可预知数据模式的大量数据时特别有用,因为它避免了冗余的数据存储和内存开销。

首先,我们定义一个 SyntheticListModel 类,它继承自 QAbstractListModel。这个模型将根据索引动态生成数据项:

#include <QAbstractListModel>
#include <QVariant>
#include <QModelIndex>class SyntheticListModel : public QAbstractListModel {Q_OBJECTpublic:SyntheticListModel(int numItems, QObject *parent = nullptr): QAbstractListModel(parent), m_numItems(numItems) {}int rowCount(const QModelIndex &parent = QModelIndex()) const override {// 在顶层,返回项的数量;否则返回0,因为这是一个列表,没有子项return parent.isValid() ? 0 : m_numItems;}QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override {if (index.isValid() && index.row() < m_numItems) {if (role == Qt::DisplayRole) {// 根据行号动态生成数据return QString("项目 %1").arg(index.row());}// 可以根据需要添加其他角色的处理}return QVariant(); // 无效索引或角色时返回无效的QVariant}private:int m_numItems; // 列表中项目的数量
};

然后,我们创建一个简单的 QStyledItemDelegate,这个委托可以根据需要自定义项的显示方式:

#include <QStyledItemDelegate>
#include <QPainter>class SimpleDelegate : public QStyledItemDelegate {Q_OBJECTpublic:using QStyledItemDelegate::QStyledItemDelegate; // 继承构造函数// 重写 paint 方法以自定义项目显示方式void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override {// 调用基类的 paint 方法进行默认的绘制QStyledItemDelegate::paint(painter, option, index);// 可以添加额外的绘制代码,如绘制边框、背景等}// 如果需要,可以重写 createEditor、setEditorData、setModelData 等方法以自定义编辑行为
};

最后,我们在 main 函数中创建 QListView,并将其与我们的自定义模型和委托相连接:

#include <QApplication>
#include <QListView>int main(int argc, char *argv[]) {QApplication app(argc, argv);// 创建列表视图QListView listView;// 创建模型,这里我们创建了 100000 个假数据项SyntheticListModel model(100000);// 创建委托SimpleDelegate delegate;// 将模型和委托设置到列表视图listView.setModel(&model);listView.setItemDelegate(&delegate);listView.show();return app.exec();
}

在这个示例中,我们展示了如何使用 QListView 和自定义的 QAbstractListModel 来动态生成数据,而不需要在内存中维护一份数据存储的副本。在实际业务中,数据可以直接从业务模块中获取,这样避免出现数据的两个副本SimpleDelegate 负责定制列表项的视觉呈现,但在这个简化的例子中,我们仅使用了默认的绘制逻辑。如果需要更复杂的项显示或编辑功能,可以在委托中进一步扩展 paint 和其他相关方法。这些内容我们在示例3中展现。

示例 3: 使用 QListView 和自定义 QAbstractListModel(解决数据如何展示问题)

实例2中没有展开SimpleDelegate 的实现,在实际开发场景中,界面展示的需求往往更加复杂,特别是QListView的View模型采用的是paint函数来呈现,和其他图形界面框架(如AndroidFramework)构造一个QWidget*控件的形式不同,paint的形式用起来更复杂,但性能天花板更高

下面是一个使用自定义模型 LargeListModel 和委托 SimpleDelegate 的例子。在这个示例中,我们将创建一个自定义的 QAbstractListModel 类,名为 LargeListModel,它将处理大量数据项。此外,我们还将扩展 SimpleDelegate 类来自定义 QListView 中项的视觉呈现。这个委托将负责绘制项的背景、文本和一些装饰元素,从而提供更丰富的用户界面。

首先,我们定义 LargeListModel 类,该类派生自 QAbstractListModel

#include <QAbstractListModel>class LargeListModel : public QAbstractListModel {Q_OBJECT
public:explicit LargeListModel(int numItems, QObject *parent = nullptr): QAbstractListModel(parent), m_numItems(numItems) {}int rowCount(const QModelIndex &parent = QModelIndex()) const override {return parent.isValid() ? 0 : m_numItems;}QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override {if (!index.isValid() || index.row() >= m_numItems)return QVariant();switch (role) {case Qt::DisplayRole:// 动态生成显示的数据return QStringLiteral("Item %1").arg(index.row());// 这里可以根据需要添加对其他角色的处理default:return QVariant();}}private:int m_numItems; // 数据项的数量
};

接下来,我们将自定义 SimpleDelegate 类,以便在 QListView 中渲染更复杂的项:

#include <QStyledItemDelegate>
#include <QPainter>class SimpleDelegate : public QStyledItemDelegate {
public:using QStyledItemDelegate::QStyledItemDelegate; // 继承构造函数void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override {// 保存当前的绘图状态painter->save();// 绘制项的背景if (option.state & QStyle::State_Selected) {painter->fillRect(option.rect, option.palette.highlight());} else {painter->fillRect(option.rect, option.palette.base());}// 绘制自定义内容,例如文本QString text = index.data(Qt::DisplayRole).toString();painter->drawText(option.rect, Qt::AlignLeft | Qt::AlignVCenter, text);// 还原绘图状态painter->restore();}// 如果需要项的大小不是默认值,可以重写 sizeHint 方法QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override {return QSize(option.rect.width(), 50); // 设置项的高度为50}
};

最后,我们在 main 函数中创建 QListView,设置自定义的模型和委托,并显示它们:

#include <QApplication>
#include <QListView>int main(int argc, char *argv[]) {QApplication app(argc, argv);// 创建自定义模型和委托LargeListModel *model = new LargeListModel(100000); // 假设有 10 万个数据项SimpleDelegate *delegate = new SimpleDelegate();// 创建并设置 QListViewQListView listView;listView.setModel(model);listView.setItemDelegate(delegate);// 设置其他视图属性,如果需要listView.setSelectionMode(QAbstractItemView::SingleSelection);listView.setAlternatingRowColors(true); // 设置交替行颜色listView.show();return app.exec();
}

在这个示例中,LargeListModel 负责提供数据项,而 SimpleDelegate 负责自定义每个项的绘制。这种方法使得处理大量数据项时能够保持高性能,同时提供了丰富的视觉呈现和用户交互能力。通过委托的 paint 方法,我们可以绘制文本、图标、背景或任何其他图形元素来增强用户界面的视觉效果。通过重写 sizeHint 方法,我们可以为每个项定制大小,以适应不同的内容和设计需求。

这种模型-视图-委托的方法为高效地处理和展示大型数据集提供了灵活的解决方案,使得开发者可以在保持应用程序性能的同时,实现复杂且具有吸引力的用户界面。

进一步优化:处理大量动态数据

以上示例已经展示了如何使用 QListView 和自定义模型以及委托来处理静态数据。但在实际应用中,我们可能需要处理动态变化的数据集,其中项目可能会被添加、移除或更新。为了保持UI的响应性和数据的一致性,我们需要在模型中正确地处理这些变化。

数据添加示例

假设我们的 LargeListModel 需要动态添加数据,我们可以在模型中实现添加数据的逻辑,并通知视图更新:

class LargeListModel : public QAbstractListModel {// ...(省略已有代码)public:// ...(省略已有代码)// 添加新项的方法void addItem(const QString &title) {const int index = itemCount;beginInsertRows(QModelIndex(), index, index);titles.append(title);checkedItems.insert(index, false);itemCount++;endInsertRows();}// ...(省略已有代码)
};// 使用示例:
int main(int argc, char *argv[]) {QApplication app(argc, argv);// ...(省略已有代码)LargeListModel* model = new LargeListModel(0); // 初始时没有数据// ...(省略已有代码)// 动态添加数据for (int i = 0; i < 100000; ++i) {model->addItem(QString("动态项目 %1").arg(i));}// ...(省略已有代码)return app.exec();
}

在这个例子中,我们通过 addItem 方法在模型中添加新的数据项。在添加数据之前和之后,我们分别调用 beginInsertRowsendInsertRows 方法,这样 QListView 就会自动更新显示新添加的数据。

数据更新示例

如果我们需要更新现有数据,我们同样需要确保视图能够得到通知:

class LargeListModel : public QAbstractListModel {// ...(省略已有代码)public:// ...(省略已有代码)// 更新某项的方法void updateItem(int index, const QString &newTitle) {if(index >= 0 && index < itemCount) {titles[index] = newTitle;QModelIndex modelIndex = createIndex(index, 0);emit dataChanged(modelIndex, modelIndex);}}// ...(省略已有代码)
};

在这里,我们通过 updateItem 方法更新一条数据,并通过 dataChanged 信号告知视图特定项的数据已经改变。createIndex 方法用来创建一个指向已更新项的 QModelIndex 对象,这是发出 dataChanged 信号所必需的。

性能注意事项

处理大量数据时,以下是一些提高性能的常见做法:

  • 使用 beginInsertRowsendInsertRows(或对应的删除和更新版本)时,请确保避免同时进行大量的单独插入或删除操作,因为这会导致视图频繁更新,从而降低性能。相反,应该批量插入或删除。
  • 避免在 data 方法中执行耗时的计算。如果需要,可以将数据缓存或使用后台线程来准备数据。
  • 如果列表项的大小是固定的,使用 setUniformItemSizes(true) 可以提高滚动和渲染的性能。
  • 如果数据的读取是昂贵的操作,考虑实现延迟加载或数据分页,这样只有当数据真正需要显示时才读取。

一个更复杂的完整例子

刚刚我们循序渐进地了解了QListView高性能大规模列表的设计思想和实现步骤,接下来我们实现一个稍微复杂的例子,这个例子在列表的每一项中增加了一个复选框和一个按钮,表示这是一个复杂列表项的呈现。

#include <QApplication>
#include <QCheckBox>
#include <QListView>
#include <QPainter>
#include <QPushButton>
#include <QStandardItemModel>
#include <QStyledItemDelegate>
#include <QAbstractListModel>
#include <QHash>
#include <QVariant>class LargeListModel : public QAbstractListModel {
public:LargeListModel(int numItems, QObject* parent = nullptr): QAbstractListModel(parent), itemCount(numItems) {titles.resize(itemCount); // 初始化标题数组for (int i = 0; i < itemCount; ++i) {titles[i] = QString("标题文本 %1").arg(i); // 生成初始标题文本}}int rowCount(const QModelIndex& parent = QModelIndex()) const override {if (parent.isValid()) {return 0;}return itemCount;}QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override {if (!index.isValid() || index.row() >= itemCount || index.row() < 0) {return QVariant();}switch (role) {case Qt::DisplayRole:return titles.at(index.row());case Qt::CheckStateRole:{auto it = checkedItems.find(index.row());if (it != checkedItems.end()) {return QVariant(it.value() ? Qt::Checked : Qt::Unchecked);}return QVariant(Qt::Unchecked);}case Qt::EditRole: // 处理编辑角色return titles[index.row()];default:return QVariant();}}bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override {if (!index.isValid() || index.row() >= itemCount || index.row() < 0)return false;switch (role) {case Qt::CheckStateRole:// 更新 checkedItems,记录复选框的状态checkedItems[index.row()] = (value.toBool());emit dataChanged(index, index, { role });return true;case Qt::EditRole:// 更新标题文本titles[index.row()] = value.toString();emit dataChanged(index, index, { role });return true;default:return false;}}Qt::ItemFlags flags(const QModelIndex& index) const override {if (!index.isValid())return Qt::NoItemFlags;// 添加 Qt::ItemIsEditable 以支持编辑return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEditable;}private:int itemCount;mutable QHash<int, bool> checkedItems; // 存储复选框的状态QVector<QString> titles; // 存储标题文本
};// 自定义委托来绘制和处理列表项
class CustomDelegate : public QStyledItemDelegate {
public:CustomDelegate(QObject* parent = nullptr) : QStyledItemDelegate(parent) {}// 绘制列表项void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override {QStyleOptionButton buttonOption;QRect buttonRect = QRect(option.rect.right() - 80, option.rect.y() + 1, 78, option.rect.height() - 2);buttonOption.rect = buttonRect;QStyleOptionButton checkboxOption;QRect checkboxRect = QRect(option.rect.x() + 5, option.rect.y() + 5, option.rect.height() - 10, option.rect.height() - 10);checkboxOption.rect = checkboxRect;checkboxOption.state |= QStyle::State_Enabled;if (index.data(Qt::CheckStateRole).toBool()) {checkboxOption.state |= QStyle::State_On;} else {checkboxOption.state |= QStyle::State_Off;}painter->save();if (option.state & QStyle::State_MouseOver) {painter->fillRect(option.rect, option.palette.light());}// 根据是否有鼠标悬停,绘制高亮背景if (option.state & QStyle::State_MouseOver) {QRect highlightRect = option.rect;painter->fillRect(highlightRect, option.palette.highlight());}// 绘制复选框QApplication::style()->drawControl(QStyle::CE_CheckBox, &checkboxOption, painter);// 绘制按钮buttonOption.text = "按钮";QApplication::style()->drawControl(QStyle::CE_PushButton, &buttonOption, painter);// 绘制文本QRect textRect = option.rect.adjusted(checkboxRect.width() + 10, 0, -buttonRect.width() - 10, 0);painter->drawText(textRect, Qt::AlignVCenter, index.data().toString());painter->restore();}// 处理事件,如复选框的点击bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index) override {if (event->type() == QEvent::MouseButtonRelease) {QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);QRect buttonRect = QRect(option.rect.right() - 80, option.rect.y() + 5, 70, option.rect.height() - 10);QRect checkboxRect = QRect(option.rect.x() + 5, option.rect.y() + 5, option.rect.height() - 10, option.rect.height() - 10);if (buttonRect.contains(mouseEvent->pos())) {// 按钮被点击qDebug() << "按钮点击,项:" << index.row();} else if (checkboxRect.contains(mouseEvent->pos())) {// 切换复选框状态bool checked = !index.data(Qt::CheckStateRole).toBool();model->setData(index, checked ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole);qDebug() << "勾选checkbox,项:" << index.row();}return true; // 事件已处理}return QStyledItemDelegate::editorEvent(event, model, option, index);}// 提供项的大小提示QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override {return QSize(option.rect.width(), 34); // 调整为所需的大小}
};int main(int argc, char *argv[]) {QApplication app(argc, argv);QListView* listView = new QListView;auto insertCount = 100000;// 构造展示10w条数据CustomDelegate* delegate = new CustomDelegate(listView);listView->setModel(new LargeListModel(insertCount));listView->setItemDelegate(delegate);// 优化性能listView->setUniformItemSizes(true);listView->setSelectionMode(QAbstractItemView::SingleSelection);listView->show();return app.exec();
}

展示效果:
在这里插入图片描述

结语

通过遵循上述模式和性能最佳实践,可以更好地创建强大的、响应迅速的 Qt 应用程序。

简而言之,在QListView体系里,QAbstractListModel解决的是“数据存哪”,而QAbstractItemDelegate解决的是数据“如何展示”。这种模型/视图和委托的架构是 Qt 高效数据处理的基石,使得复杂的UI设计和数据操作变得可管理和可扩展。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/27763.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

面试-NLP八股文

机器学习 交叉熵损失&#xff1a; L − ( y l o g ( y ^ ) ( 1 − y ) l o g ( 1 − ( y ^ ) ) L-(ylog(\hat{y}) (1-y)log(1-(\hat{y})) L−(ylog(y^​)(1−y)log(1−(y^​))均方误差&#xff1a; L 1 n ∑ i 1 n ( y i − y ^ i ) 2 L \frac{1}{n}\sum\limits_{i1}^{n}…

大模型学习之GLM结构

探索GLM&#xff1a;一种新型的通用语言模型预训练方法 随着人工智能技术的不断进步&#xff0c;自然语言处理&#xff08;NLP&#xff09;领域也迎来了革命性的发展。OpenAI的ChatGPT及其后续产品在全球范围内引起了广泛关注&#xff0c;展示了大型语言模型&#xff08;LLM&a…

分离式网络变压器与传统网络变压器在电路设计中如何选择?

Hqst盈盛&#xff08;华强盛&#xff09;电子导读&#xff1a;今天分享的是&#xff1a;分离式网络变压器与传统网络变压器在电路设计中如何选择&#xff1f; 首先&#xff0c;我们要了解传统网络变压器和分离式网络变压器在设计上主要有以下不同点&#xff1a; 1、传统网络变…

​​Vitis HLS 学习笔记--添加 RTL 黑盒函数

目录 1. 简介 2. 用法详解 2.1 需要的文件 2.1.1 RTL 函数签名 2.1.2 黑盒 JSON 描述文件 2.1.3 RTL IP 文件 2.2 操作步骤 3. 总结 1. 简介 Vitis HLS 工具可以将现有的 Verilog RTL IP&#xff08;即硬件描述语言编写的模块&#xff09;集成到 C/C HLS 项目中。通过…

专家解读 | NIST网络安全框架(3):层级配置

NIST CSF在核心部分提供了六个类别的关键功能和子功能&#xff0c;并围绕CSF的使用提供了层级&#xff08;Tier&#xff09;和配置&#xff08;Profile&#xff09;两种工具&#xff0c;使不同组织和用户更方便有效地使用CSF&#xff0c;本文将深入探讨CSF层级和配置的主要内容…

【PL理论】(24) C- 语言:有块的作用域 | 更新的语法 | 新的语义域 | 环境 vs. 内存

&#x1f4ad; 写在前面&#xff1a;我们将再次扩展之前的C语言&#xff0c;让我们向这种语言引入“作用域”的概念。 目录 0x00 C- 语言&#xff1a;有块的作用域 0x01 C- 语言&#xff1a;更新的语法 0x02 新的语义域 0x03 环境 vs. 内存 0x00 C- 语言&#xff1a;有块的…

Golang | Leetcode Golang题解之第145题二叉树的后序遍历

题目&#xff1a; 题解&#xff1a; func reverse(a []int) {for i, n : 0, len(a); i < n/2; i {a[i], a[n-1-i] a[n-1-i], a[i]} }func postorderTraversal(root *TreeNode) (res []int) {addPath : func(node *TreeNode) {resSize : len(res)for ; node ! nil; node n…

大语言模型QA

Q:关于 Yi-9B 通过 input/output cosine 来分析模型,可能文档里没有把前提说明白。该指标确实存在你们提到的不同模型大小不可比的问题。所以我们比较的是同一个模型在不同训练阶段,以及 layer 深度相同的dense models 之间的比较。除了发现yi-6B/34B 随着训练 tokens 的增加…

Polkadot <> Kusama 桥:打造无信任互操作性的开创性范例

原文&#xff1a;https://www.parity.io/blog/trustless-interoperability 作者&#xff1a;Adrian Catangiu&#xff5c;Rust 区块链核心工程师&#xff0c;Parity Technologies 编译&#xff1a;OneBlock Polkadot <> Kusama 桥是无信任互操作性的开创性范例。本文深…

TCP相关细节

1. 常用TCP参数 1.1 ReceiveBufferSize ReceiveBuffersize指定了操作系统读缓冲区的大小&#xff0c; 默认值是8192(如图5-10 所示)。在第4章的例子中,会有"假设操作系统缓冲区的长度是8" 这样的描述,可通过socket.ReceiveBufferSize 8 实现。当接收端缓冲区满了的时…

实用软件下载:XMind 2024最新安装包及详细安装教程

​XMind不仅是一款易用且功能强大的思维导图软件&#xff0c;也是一个开源项目。XMind以构建一个社区向全球提供领先的跨平台思维导图和头脑风暴软件为目标&#xff0c;以帮助用户提升效率。XMind公司是XMind开源项目的主要代码贡献者&#xff0c;与此同时&#xff0c;我们欢迎…

Stable Diffusion本地化部署详细攻略

一、硬件要求 内存&#xff1a;至少16GB 硬盘&#xff1a;至少60GB以上的磁盘空间&#xff0c;推荐SSD固态硬盘 显卡&#xff1a;推荐NVIDIA显卡 显存&#xff1a;至少4GB Stabl Diffusion因为是在本地部署&#xff0c;对显卡的要求比较高&#xff0c;如果经济能力可以的话…

AI大模型爆发,你还不学就晚了!抓住时代机遇,快速入门指南!

AI大模型风起云涌&#xff0c;你准备好乘风破浪了吗&#xff1f; 在一个阳光明媚的午后&#xff0c;小李坐在自己的工位上&#xff0c;眼前的代码如同繁星般繁多。他是一名资深的软件工程师&#xff0c;但在最近的技术浪潮中&#xff0c;他却感到了一丝不安。他的朋友圈里&…

RN6752V1 高性能AHD转MIPIDVPBT656BT601芯片方案,目前适用于车载方案居多

RN6752V1描述&#xff1a; RN6752V1是一种模拟高清晰度&#xff08;模拟高清&#xff09;视频解码器IC&#xff0c;专为汽车应用而设计。它集成了所有必要的功能块&#xff1a; AFE&#xff0c;PLL&#xff0c;解码逻辑&#xff0c;MIPI和I2C接口等&#xff0c;在一个小的5mm …

LLM资料大全:文本多模态大模型、垂直领域微调模型、STF数据集、训练微调部署框架、提示词工程等

前言 自ChatGPT为代表的大语言模型&#xff08;Large Language Model, LLM&#xff09;出现以后&#xff0c;由于其惊人的类通用人工智能&#xff08;AGI&#xff09;的能力&#xff0c;掀起了新一轮[自然语言处理]领域的研究和应用的浪潮。尤其是以ChatGLM、LLaMA等平民玩家都…

【ARM Cache 及 MMU 系列文章 6.5 -- 如何进行 Cache miss 统计?】

请阅读【ARM Cache 及 MMU/MPU 系列文章专栏导读】 及【嵌入式开发学习必备专栏】 文章目录 ARM Cache Miss 统计Cache 多层架构简介Cache 未命中的类型Cache 未命中统计Cache miss 统计代码实现Cache Miss 统计意义ARM Cache Miss 统计 在ARMv8/v9架构中,缓存未命中(Cache …

人工智能在风险管理中的创新之路

随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;已经渗透到我们生活的方方面面&#xff0c;尤其在风险管理领域&#xff0c;其展现出的巨大潜力令人瞩目。风险管理&#xff0c;作为一个涉及广泛领域的复杂系统&#xff0c;正逐渐依赖于AI技术来提升效率和准…

简单了解CPU的工作原理

目录 一、基本结构以及对应功能 &#xff08;1&#xff09;基本结构 &#xff08;2&#xff09;几个重要寄存器的详细介绍 操作码 (Opcode) 操作数 (Operands) 指令表 (Instruction Table) 第一个&#xff1a;程序计数器 (PC) 第二个&#xff1a;指令寄存器 (IR&#x…

【Arthas案例】某应用依赖两个GAV不同但包含两个相同全限定类名StaticLoggerBinder,引起log4j.Level类找不到异常

3分钟内解决问题 两个不同的GAV依赖冲突&#xff0c;包含相同全限定类名&#xff0c;引起ClassNotFoundException Maven依赖的三坐标体系GAV(G-groupId&#xff0c;A-artifactId&#xff0c;V-version) 【案例1】某应用依赖两个GAV不同的jar&#xff0c;但包含两个相同全限定类…

探索互联网寻址机制 | 揭秘互联网技术的核心,解析网络寻址

揭秘互联网技术的核心&#xff0c;解析网络寻址题 前提介绍局域网地址IP地址的分配方式动态IP分配机制内部网&#xff08;intranet&#xff09;ICANN负责IP分配DHCP协议获取IP地址 域名系统域名是什么域名工作方式hosts文件存储域名映射关系DNS分布式数据库DNS域名解析 Java进行…