在最近的项目中,发现执行 Qt 程序时,有些情况下的 CPU 占用率奇高,最高高达 100%。项目跑在嵌入式板子上,最开始使用 EGLFS 插件,但是由于板子没有单独的鼠标层,导致鼠标移动起来卡顿,很不流畅,所以换成了 LinuxFB 插件。但是如果 CPU 占有率高了的话,也会导致鼠标卡顿,因为鼠标是由 Qt 应用程序层负责绘制的,如果应用程序 CPU 占有率高了的话,也会导致鼠标绘制缓慢,导致鼠标卡顿。
所以要解决 CPU 占有率高的问题,进行性能优化,本文对项目中容易出现的问题现象与解决办法进行了记录。
现象
代码逻辑控制的 UI 控件(包括 QWidget)频繁刷新,或者某个动作频繁执行。UI 刷新在一定程度上会对CPU占用率有影响,若频繁刷新控件(不论是重绘还是更新数据),都会十分消耗 CPU 占用率。例如一个时间 Label,采用定时器设置时间,如果定时器的定时间隔过短,比如 10ms 甚至更短,就会比较消耗 CPU 占用率。
解决方法
所以自定义 UI 控件时就需要注意避免频繁刷新;定时器的间隔时间也要合理设置,避免过短或过长。
这个情况很常见,但相关内容很多不方便放在这,可以看我的下一篇博客: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 资源,尤其这个自定义控件本身比较消耗资源的话。
解决方法
现象
如果执行了一个操作,然后短时间内多次调用 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 的线程提供了以下几种优先级(由低到高排列),按照实际情况去设置优先级,可以提高界面的流畅度。
现象
项目里有一个子线程的代码结构是这样的。
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,可以检查相关代码进行优化。
我在Rails应用程序中使用CarrierWave/Fog将视频上传到AmazonS3。有没有办法判断上传的进度,让我可以显示上传进度如何? 最佳答案 CarrierWave和Fog本身没有这种功能;你需要一个前端uploader来显示进度。当我不得不解决这个问题时,我使用了jQueryfileupload因为我的堆栈中已经有jQuery。甚至还有apostonCarrierWaveintegration因此您只需按照那里的说明操作即可获得适用于您的应用的进度条。 关于ruby-on-r
在前面两节的例子中,主界面窗口的尺寸和标签控件显示的矩形区域等,都是用C++代码编写的。窗口和控件的尺寸都是预估的,控件如果多起来,那就不好估计每个控件合适的位置和大小了。用C++代码编写图形界面的问题就是不直观,因此Qt项目开发了专门的可视化图形界面编辑器——QtDesigner(Qt设计师)。通过QtDesigner就可以很方便地创建图形界面文件*.ui,然后将ui文件应用到源代码里面,做到“所见即所得”,大大方便了图形界面的设计。本节就演示一下QtDesigner的简单使用,学习拖拽控件和设置控件属性,并将ui文件应用到Qt程序代码里。使用QtDesigner设计界面在开始菜单中找到「Q
我想从then子句中访问case语句表达式,即food="cheese"casefoodwhen"dip"then"carrotsticks"when"cheese"then"#{expr}crackers"else"mayo"end在这种情况下,expr是食物的当前值(value)。在这种情况下,我知道,我可以简单地访问变量food,但是在某些情况下,该值可能无法再访问(array.shift等)。除了将expr移出到局部变量然后访问它之外,是否有直接访问caseexpr值的方法?罗亚附注我知道这个具体示例很简单,只是一个示例场景。 最佳答案
我正在使用Ruby解决一些ProjectEuler问题,特别是这里我要讨论的问题25(Fibonacci数列中包含1000位数字的第一项的索引是多少?)。起初,我使用的是Ruby2.2.3,我将问题编码为:number=3a=1b=2whileb.to_s.length但后来我发现2.4.2版本有一个名为digits的方法,这正是我需要的。我转换为代码:whileb.digits.length当我比较这两种方法时,digits慢得多。时间./025/problem025.rb0.13s用户0.02s系统80%cpu0.190总计./025/problem025.rb2.19s用户0.0
我正在寻找一个用ruby演示计时器的在线示例,并发现了下面的代码。它按预期工作,但这个简单的程序使用30Mo内存(如Windows任务管理器中所示)和太多CPU有意义吗?非常感谢deftime_blockstart_time=Time.nowThread.new{yield}Time.now-start_timeenddefrepeat_every(seconds)whiletruedotime_spent=time_block{yield}#Tohandle-vesleepinteravalsleep(seconds-time_spent)iftime_spent
如果用户是所有者,我有一个条件来检查说删除和文章。delete_articleifuser.owner?另一种方式是user.owner?&&delete_article选择它有什么好处还是它只是一种写作风格 最佳答案 性能不太可能成为该声明的问题。第一个要好得多-它更容易阅读。您future的自己和其他将开始编写代码的人会为此感谢您。 关于ruby-on-rails-如果条件与&&,是否有任何性能提升,我们在StackOverflow上找到一个类似的问题:
如果我想使用“create”构建策略创建和实例,然后想使用“attributes_for”构建策略进行验证,是否可以这样做?如果我在工厂中使用序列?在Machinistgem中有可能吗? 最佳答案 不太确定我是否完全理解。而且我不是机械师的用户。但听起来您只是想做这样的事情。@attributes=FactoryGirl.attributes_for(:my_object)my_object=MyObject.create(@attributes)my_object.some_property.should==@attributes
我编写了一个Ruby应用程序,它可以解析来自不同格式html、xml和csv文件的源中的大量数据。我如何找出代码的哪些区域花费的时间最长?有没有关于如何提高Ruby应用程序性能的好资源?或者您是否有任何始终遵循的性能编码标准?例如,你总是用加入你的字符串吗?output=String.newoutput或者你会使用output="#{part_one}#{part_two}\n" 最佳答案 好吧,有一些众所周知的做法,例如字符串连接比“#{value}”慢得多,但是为了找出您的脚本在哪里消耗了大部分时间或比所需时间更多,您需要进行分
我在Rails中有一个具有以下方法的应用程序,该方法可以加密和解密文本并与Java客户端通信。defencrypt(string,key)cipher=OpenSSL::Cipher::AES.new(128,:CBC)cipher.encryptcipher.padding=1cipher.key=hex_to_bin(Digest::SHA1.hexdigest(key)[0..32])cipher_text=cipher.update(string)cipher_textexcenddefhex_to_bin(str)[str].pack"H*"enddefbin_to_hex(
LL库和HAL库简介LL:Low-Layer,底层库HAL:HardwareAbstractionLayer,硬件抽象层库LL库和hal库对比,很精简,这实际上是一个精简的库。LL库的配置选择如下:在STM32CUBEMX中,点击菜单的“ProjectManager”–>“AdvancedSettings”,在下面的界面中选择“AdvancedSettings”,然后在每个模块后面选择使用的库总结:1、如果使用的MCU是小容量的,那么STM32CubeLL将是最佳选择;2、如果结合可移植性和优化,使用STM32CubeHAL并使用特定的优化实现替换一些调用,可保持最大的可移植性。另外HAL和L