Qt 性能优化:CPU占有率高的现象和解决办法

2023-05-16

一、前言

在最近的项目中,发现执行 Qt 程序时,有些情况下的 CPU 占用率奇高,最高高达 100%。项目跑在嵌入式板子上,最开始使用 EGLFS 插件,但是由于板子没有单独的鼠标层,导致鼠标移动起来卡顿,很不流畅,所以换成了 LinuxFB 插件。但是如果 CPU 占有率高了的话,也会导致鼠标卡顿,因为鼠标是由 Qt 应用程序层负责绘制的,如果应用程序 CPU 占有率高了的话,也会导致鼠标绘制缓慢,导致鼠标卡顿。

所以要解决 CPU 占有率高的问题,进行性能优化,本文对项目中容易出现的问题现象与解决办法进行了记录。

二、UI 控件频繁刷新

现象

代码逻辑控制的 UI 控件(包括 QWidget)频繁刷新,或者某个动作频繁执行。UI 刷新在一定程度上会对CPU占用率有影响,若频繁刷新控件(不论是重绘还是更新数据),都会十分消耗 CPU 占用率。例如一个时间 Label,采用定时器设置时间,如果定时器的定时间隔过短,比如 10ms 甚至更短,就会比较消耗 CPU 占用率。

解决方法

所以自定义 UI 控件时就需要注意避免频繁刷新;定时器的间隔时间也要合理设置,避免过短或过长。

三、paintEvent 高频绘图

这个情况很常见,但相关内容很多不方便放在这,可以看我的下一篇博客:Qt 性能优化之二:绘制视频方案选择

四、优化界面刷新

现象
项目中有一项功能是在子线程里读数据,数据若发生变化了就发送信号,在槽里更新界面。程序运行的时候会出现数据变化很频繁的情况,也导致更新界面的信号在短时间内被触发很多次,大大损耗了程序的性能。

解决方法
因为人眼捕获的帧率有限,所以界面显示不需要太快的刷新速度,把信号槽更新界面改为用定时器更新界面,就能避免某一时间段数据变化过频导致的卡顿问题。

五、样式表导致绘图事件频繁调用

现象

QWidget:主窗口,背景利用setStyleSheet设置,同时重写paintEvent事件(QWigdet 的 paintEvent 默认为空):

void mainWidget::paintEvent(QPaintEvent *event)
{
    QStylePainter painter(this);
    QStyleOption opt;
    opt.initFrom(this);
    opt.rect = this->rect();
    painter.drawPrimitive(QStyle::PE_Widget,opt);
    QWidget::paintEvent(event);
}

主窗口上有众多不规则按键(某些按键组合成按键组,按下一个按键按键组的外观一起改变,通过设置样式表实现),每个按键都setMask设置有效区域,按键在按下,松开,选中都会有不同的样式,通过setStyleSheet设置。

结果发现,按键在响应过程中非常慢,top 看一下 CPU 占用率在点击按键时达到了 90%+,重绘事件在控件外观发生变化时会被调用。

猜测:在操作按键(按下,松开,点击)时在其槽函数改变按键的样式表,按键为主窗口的子控件。所以也会操作到主窗口的样式表。也即,主窗口的重绘事件也被调用。也就导致了每点击一个按键,最少也要调用三次主窗口的重绘事件。重复多次调用重绘事件使得在嵌入式平台中响应速度变慢。

解决方法

主窗口不使用样式表方式设置背景,改用调色板方式,此时主窗口样式表为空:

mainWidget::mainWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::mainWidget)
{
    QPixmap pixmap;
    QPalette palette;
    setWindowFlags(Qt::FramelessWindowHint);
    pixmap.load(":/images/res/mianbackground.png");
    palette.setBrush(QPalette::Window, QBrush(pixmap));
    setPalette(palette);
    ui->setupUi(this);
···
}

此时操作按键,CPU 占用率已经大大减小了,基本不会有超过 10% 的情况。

六、短时间内创建大量控件

现象

如果短时间内创建多个控件,例如一个 10x10 的控件网格,测试发现也会比较消耗 CPU 资源,尤其这个自定义控件本身比较消耗资源的话。

解决方法

  • 优化自定义控件,减少单个控件创建所需的资源;
  • 每创建一个或者一部分控件后,加点 sleep() 延时,但是这样会导致创建控件比较慢,视觉效果也不是很好,看怎么取舍了;
  • 如果是创建大量只需要显示的控件,例如一些图标控件,可以考虑使用 Qt 的图形视图 Graphics View 框架,创建图元比创建 QWidegt 控件快多了,但是需要考虑 QWidget 与 QGraphicsScene 的嵌套使用。

七、短时间内多次调用 qDebug() 打印造成卡顿

现象

如果执行了一个操作,然后短时间内多次调用 qDebug() 打印,测试发现也会比较消耗 CPU 资源。

解决方法

所以平时不要加太多打印,正式发布后一些调试打印要即使删除。如果为了测试方便,有些打印不想删除,可以选择正式版本关闭打印,测试时可以使用终端执行./proName d来运行应用程序以输出打印,d是要输出打印的后缀。代码如下:

// 默认先关闭qDebug()打印,以减少短时间内输出大量qDebug()打印造成的卡顿
QLoggingCategory::defaultCategory()->setEnabled(QtDebugMsg, false);
// 如果执行./proName d,则开放打印
if(QString::fromUtf8(argv[1]) == "d") {
	printf("Open qDebug!!!!!\n");
	QLoggingCategory::defaultCategory()->setEnabled(QtDebugMsg, true);
}

八、设置线程优先级

现象
项目中有多线程的操作,所有的线程都是用默认的QThread::InheritPriority优先级。因为设备的性能有限,让所有的线程都以高优先级去运行,主线程被过多地占用资源,导致界面刷新卡顿的问题。

解决方法
Qt 的线程提供了以下几种优先级(由低到高排列),按照实际情况去设置优先级,可以提高界面的流畅度。

  • QThread::IdlePriority
  • QThread::LowestPriority
  • QThread::LowPriority
  • QThread::NormalPriority
  • QThread::HighPriority
  • QThread::HighestPriority
  • QThread::TimeCriticalPriority
  • QThread::InheritPriority

九、检查子线程的延时操作

现象
项目里有一个子线程的代码结构是这样的。

void run() {
	while (true) {
		if (...) {
   			continue;
		}
	
		..... //operate
		msleep(20);
	}
}

线程在延时状态下是会把 CPU 交给其它线程的,避免不停地抢占 CPU,以上代码虽然加了延时,但前面有一个判断操作,如果满足了条件,就直接调用continue,如果这个判断条件一直都是满足的,那就会不停地 continue,代码也就变成了以下形式。

void run() {
	while (true) {
   		continue;
	}
}

等同于一个死循环,这样会大大影响程序的效率。

解决方法
在每个 continue 前添加延时。

void run() {
	while (true) {
		if (...) {
			msleep(20);
   			continue;
		}
	
		..... //operate
		msleep(20);
	}
}

或者避免使用 continue:

void run() {
	while (true) {
		if (...) {
			..... //operate
		}
	
		msleep(20);
	}
}

另外多线程,要合理的使用 sleep。对于while(1)中有耗时处理的,添加Sleep(0)就可以;对于没有耗时处理的,添加Sleep(0)就不行了,Sleep(1),Sleep(5)都行。

十、优化数据库查询方式

如果表中数据量大或者查询频率高,可以使用 map 容器来存放,以空间换时间,减少查询损耗。或者调整数据结构,将 2,3 百条数据的数组改成 map 结构储存等等。

十一、通信协议的优化

可以通过优化通信协议来减少客户端和服务端的计算量。

十二、减少不必要的IO操作

IO 操作是比较耗时的,常见的 IO 有通信 IO 和文件 IO,可以检查相关代码进行优化。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt 性能优化:CPU占有率高的现象和解决办法 的相关文章

  • 尚硅谷react课程-day03

    目录 1 对类组件中方法总结 xff1a 2 组件实例第二大属性prop方法 2 1 react中prop方法解构赋值 3 对porps传递的数据进行限制 4 类式组件中构造器与props关系 1 对类组件中方法总结 xff1a 1 cla
  • 配置树莓派4B+Ubuntu-22.04.2+Intel Realsense T265

    准备 xff1a 树莓派4b Ubuntu 22 04 2 T265 开始玩树莓派和T265时配置环境配置了半天 xff0c 各种报错 xff0c 在不熟悉这些的情况下想要配置一个稳定不报错的系统就只有不断的尝试 xff0c 再重装了10次
  • 节点基础~节点操作

    一 创建和添加节点 1 创建节点 document createElement 方法创建由tagName指定的 HTM元素 因为这些元素原先不存在 xff0c 是根据我们的需求动态生成的 xff0c 所以我们也称为动态创建元素节点 2 添加
  • workerman-chat启动后,前台无法访问

    去阿里云的安全组 xff0c 添加规则 xff1a 55151和7272 启动GatewayWorker的命令 xff0c 注意 xff1a 这个需要在linux服务器 xff0c 到api文件夹下运行 xff08 就是有think文件 x
  • 基于FreeRTOS实现温湿度识别

    实验说明 xff1a 本实验主要利用freeRTOS创建多任务实现温湿度检测与点亮LED xff0c 并在串口上输出相应温湿度和LED亮灭情况 xff1b 一 实验用材 1 DHT11温湿度传感器模块 2 stm32f103c8t6最小系统
  • 操作系统学习笔记

    文章目录 一 概述1 什么是操作系统2 操作系统的作用3 操作系统的发展史4 操作系统的分类5 现代操作系统的主要特点 二 进程控制1 进程的基本概念2 进程控制的基本概念3 同步和互斥4 进程通信5 线程和管程的基础概念6 死锁 三 处理
  • django注册功能密码加密存储

    1 编写模型类 class User models Model username 61 models CharField max length 61 16 verbose name 61 39 账号 39 password 61 model
  • Node.js【未完成】

    Node js node介绍和环境安装 Node js 简介 1 什么是 Node js Node js is a JavaScript runtime built on Chrome s V8 JavaScript engine Node
  • Pygame简介

    第一课Pygame简介 Pygame 是一个游戏库 xff0c 通常用于在 Python 中创建 2 D 游戏 它具有许多重要功能 xff0c 例如碰撞检测 声音和音乐 图形 事件系统等等 Pygame安装 在我们向您介绍任何 Pygame
  • Vue2---生命周期钩子

    生命周期钩子 所有生命周期钩子的 this 上下文将自动绑定至实例中 xff0c 因此你可以访问 data computed 和 methods 这意味着你不应该使用箭头函数来定义一个生命周期方法 会使this指向window 1 befo
  • MySQL--复合查询--内外链接--0422

    注 xff1a 为了方便查看 mysql语句会有突然的换行 xff0c 书写时请勿模仿 目录 1 单表查询回顾 显示工资最高的员工的名字和工作岗位 显示工资高于平均工资的员工信息 2 多表查询 比如需要查询雇员名字和所在部门编号及部门名字
  • 以符合人类阅读的方式打印php数组

    在程序开发过程中 xff1b 打印数据进行查看调试是非常频繁的 xff1b 如果没有一种易于阅读的样式那是相当痛苦的 xff1b 先定义一个数组 xff1b array 61 array 39 t0 39 61 gt 39 test0 39
  • 12.【openCV常用函数模板】

    opency常用关键字 1 头文件的引用2 命名空间的引用3 读入文件的引用4 处理图像的数据结构5 定义窗口的引用6 自定义窗口长宽度的引用7 展示窗口的引用8 窗口展示时间的引用9 清除窗口的引用10 举列子10 1代码展示 10 2效
  • 利用novnc登录绕过WFA

    0x00 简介 前端时间看了一个新闻说是一个安全人员研究使用webVNC来钓鱼绕过MFA多因子验证 xff0c 因为现在很多环境钓鱼抓到的账号密码 xff0c 在登录时候可能会要求输入安全码或者PIN马之类的东西 xff0c 学名叫做MFA
  • 图像分割损失函数OhemCELoss

    OhemCELoss函数简介 OhemCELoss函数 xff08 Online hard example mining cross entropy loss 的缩写 xff09 分割任务中的OhemCELoss函数 xff1a 其实就是分
  • 02_FreeRTOS内核实现---任务的定义与任务切换

    一 什么是任务 在多任务系统中 xff0c 我们根据功能的不同 xff0c 把整个系统分割成多个独立且无法返回的函数 xff0c 这种函数称之为任务 二 创建任务 1 定义任务栈 在多任务系统中 xff0c 每个任务都是独立的 xff0c
  • ROS学习笔记1:Ubuntu20.04系统安装图文讲解(双系统,机械硬盘)

    系列前言 xff1a 本人BIT机械专业大三学生 xff0c 可以说是计算机小白 近年来学校以咱们 智能制造与智能车辆班 为试验班对机械专业进行探索性课改 xff0c 加入了大量控制类课程 xff08 数据结构 xff0c ROS xff0
  • ROS学习笔记3:ROS架构(了解)

    笔记3不涉及实际操作 xff0c 主要是用自己的语言和思路简略整理了 ROS机器人开发实践 一书第2章内容 第一次看这一章的内容会有不知道在讲什么的感觉 xff0c 但这一章的内容确实对后续实践操作章节的理解有非常大的帮助 一 ROS架构
  • SLAM学习笔记2:SLAM的数学表述

    1 SLAM问题 xff1a 在了解了SLAM中各个模块的组成和主要功能后 xff0c 我们将上升到理性层次 xff0c 用数学语言来描述SLAM过程 现在假设由无人车搭载传感器 对于传感器来说 xff0c 虽然它的运动是时间连续的 xff
  • ROS学习笔记10:TF坐标变换(ROS常用组件)

    前言 xff1a 机器人本体和机器人的工作环境中往往存在大量的组件元素 xff0c 在机器人设计和应用中会涉及不同组件的位置和姿态 xff0c 这就需要引入坐标系和坐标变换的概念 一 机器人中空间描述和变换 xff1a 1 位置描述 xff

随机推荐

  • ROS学习笔记11:launch启动文件(ROS常用组件)

    一 launch启动文件介绍 xff1a 上节的海龟跟随实验 xff0c 输入的指令比较繁杂 xff0c 很容易输错命令 对于这种多节点任务 xff0c 可以使用启动文件 启动文件是ROS中一种可以通过xml文件 xff0c 同时启动多个节
  • 学习ARM架构,系统移植和驱动开发总结

    本次结束了对ARM架构 xff0c 系统移植和驱动开发的学习 xff0c 它们都是属于底层 xff0c 难度想对都比较的难一点 xff0c 但先学习arm架构之后去学习系统移植和驱动开发 xff0c 会使自己对系统移植和驱动开发容易理解点
  • Robocup2D环境搭配以及安装(Ubuntu18.04)

    个人是看过很多安装教程并且在一次次实验成 xfeff 功后得出的成果 xff1a 首先 xff0c 在gitee网站下载安装所需的文件夹 xfeff gitee网站下载zip压缩包 其次 xff0c 进行依赖库的安装 终端输入 sudo a
  • 树莓派配置网络实现ssh登录

    上面一篇文章我实现了串口方式访问树莓派 xff0c 可以实现树莓派开发 xff0c 但每次都需要接线 xff0c 比较麻烦所以我们可以对树莓派进行配置让他可以用IP地址登录 1 配置树莓派接入网络 sudo nano etc wpa sup
  • 字符串查找函数strstr

    前言 xff1a 本章我们将学习如何用strstr函数在字符串中查找是否存在指定的字符串 strstr 功能 xff1a 在一个字符串中查找是否存在指定的字符串 xff08 定位子字符串 xff09 cplusplus介绍如下 xff1a
  • Module not found: Error: Can‘t resolve ‘querystring‘ in ‘xxxxxxxxx‘

    解决办法 request js里面 import qs from 34 querystring 34 改为import qs from 34 qs 34
  • 【C语言】初学者写基础代码的基本步骤

    一 写代码 xff08 底阿妈 xff09 步骤 xff1a 1 创建一个项目 2 创建一个源文件 什么是源文件 xff1a xxxx c c开头的叫源文件 xxxx h h开头的叫头文件 3 写代码 xff08 底阿妈 xff09 one
  • ROS新手学习路线

    希望这些信息能够帮助你学习ROS 如果你有任何其他问题 xff0c 请随时告诉我 安装ROS 首先 xff0c 你需要在你的计算机上安装ROS 请参阅官方文档中的 安装 章节 xff0c 了解如何在你的系统上安装ROS xff1a http
  • JAVA学习心得体会

    这周是考试结束第一周 xff0c 刚开始继续学习JAVA时 xff0c 短时间不学习就感觉遗忘了许多有关JAVA的知识 xff0c 所以及时的复习所学内容是真的很重要 通过学长学姐的介绍 xff0c 我发现Typora记笔记是真的很方便 x
  • Ubuntu18.04在ROS下利用realsenseD435i相机实时运行ORB-SLAM2

    1 安装realsenseD435i的SDK Librealsense 可以参照这位博主 6条消息 Ubuntu18 04 43 ROS melodic 安装使用 InterRealSenseD435i SDK2和RealSense ROS
  • opencv-python识别魔方特定颜色方块,并输出各方块中心坐标

    先叠个甲 xff08 作者寒假才开始自学opencv xff0c 做题练手 xff0c 还不是很熟练 xff0c 如果有不正确或者有更好的方法 xff0c 欢迎在评论区指出 xff09 题目 xff1a 从网上寻找任一魔方图片 xff0c
  • Git教程学习笔记及VScode中Git使用

    文章目录 前言1 配置git2 创建版本库3 版本回退4 工作区和暂存区5 添加远程仓库6 分支管理处理bug分支多人协作 7 标签管理8 自定义git9 VScode中的Git使用 前言 欢迎通过我的个人博客看本篇文章https sunm
  • Qt的基本数据类型

    1 1 基本数据类型 qint8 signed charqint16 signed shortqint32 signed intqint64 long long int int64 on Windows qreal doublequint8
  • Qt——Javascript/Qt交互、脚本化

    Qt提供了对Javascript的良好支持 如果查阅过文档你就知道Qt有两个不同的Js封装引擎 xff1a QScriptEngine QJSEngine QScriptEngine出现的比较早 xff08 自Qt4 3始 xff09 xf
  • QT自绘标题和边框

    在QT中如果想要自绘标题和边框 xff0c 一般步骤是 xff1a 1 xff09 在创建窗口前设置Qt FramelessWindowHint标志 xff0c 设置该标志后会创建一个无标题 无边框的窗口 2 xff09 在客户区域的顶部创
  • Qt:QSqlQuery

    0 说明 QSqlQuery提供了执行SQL代码的方法 QSqlQuery封装了在QSqlDatabase中查询 检索数据的相关函数 它可以用来执行如SELECT INSERT UPDATE DELETE等方法 xff0c 也可以执行如CR
  • Qt - 读取GPS数据

    1 GPS型号为ublox xff08 EVK M8L xff09 xff0c 配有USB接口 xff0c Qt版本5 7 2 实现步骤 xff1a 1 实现串口通信 采用Qt5 7 内置的串口操作类QSerialPort和QSerialP
  • QT打包的两种方式

    QT打包的两种方式 xff1a 一个是QT5自带的windeployqt xff08 不需要下载安装 xff09 xff0c 它可以找到程序 xff08 exe xff09 用到的所有库文件 xff0c 并且都拷贝到exe程序的当前文件 此
  • Qt使用FFmpeg播放视频

    一 使用场景 因为项目中需要加载MP4播放开机视频 xff0c 而我们的设备所使用的架构为arm架构 xff0c 其中缺乏一些多媒体库 安装这些插件库比较麻烦 xff0c 所以最终决定使用FFmpeg播放视频 二 下载编译ffmpeg库 2
  • Qt 性能优化:CPU占有率高的现象和解决办法

    一 前言 在最近的项目中 xff0c 发现执行 Qt 程序时 xff0c 有些情况下的 CPU 占用率奇高 xff0c 最高高达 100 项目跑在嵌入式板子上 xff0c 最开始使用 EGLFS 插件 xff0c 但是由于板子没有单独的鼠标