QT中QTimer的循环时间与槽函数执行时间以及在事件循环中触发,不同时间的结果分析

目录

当循环时间小于槽函数时间时: 

当循环间隔时间大于槽函数时间时:

当存在两个定时器器,其中一个还是间隔100ms,另一个间隔1000ms: 

当两个定时器的循环周期大于槽函数执行时间时

当在主程序中添加一个for循环后 

当在for循环中加上人为触发其他事件QCoreApplication::processEvents() 后

当把for循环放到子线程中运行时 

当在子线程中定义定时器时 


在使用QT过程中,新手在QTimer,多线程,信号槽不是很了解的时候,常常容易感觉有点乱,最近自己编写了几个案例,仔细研究了一下定时器,多线程,信号槽之间的相互关系。

个人总结:

线程是程序运行的基本单位,GUI编程中,主线程既是GUI线程,其他都是子线程,在创建子线程时,个人还是建议用movethread的方式。这种方式能将整个对象的生命周期都放置到一个独立的子线程中,对象的所有操作都将在子线程中完成。很符合线程的概念。

线程之间优先采用信号槽的方式通讯。保证线程安全的同时,也能保证一些需要时序控制的过程的安全可控运行。省去了线程同步的麻烦。

信号槽之所以能省去线程同步的麻烦,正是因为事件循环的作用,信号发送到子线程后,将按发送先后的顺序依次插入到子线程的事件队列中,当前面的事件处理完成后,依次执行后续事件。这个方式就能起到线程同步的作用。

而通过movethread的创建的子线程,当start的时候,默认是会开启一个子线程的事件循环。在非直接连接的信号槽绑定后,所有的信号都将在子线程的事件循环中依次完成。

而定时器的运行,也是在线程的事件循环中实现的,当timeout信号发出后,在创建该定时器的线程中将触发对应槽函数。也即在哪个线程创建,对应的timeout就在哪个线程的事件循环中执行。

线程中的程序的执行是串行的,所以信号槽,定时器触发都是按其信号的发送时间来顺序执行。

正是因为这样,当有多个定时器时,对应的槽函数的执行时间就一定得注意了,最好不要超过定时器的设置时间,因为一旦超过,定时器设置的定时时间将不是自己所设定的定时周期执行。很重要。

但是当在子线程中执行while循环时,由于线程是串行工作,没有退出while时,将阻塞事件循环中的其他所有事件。这时需要好好考虑子线程的作用,以及需要完成的工作都有哪些,以及相关动作是否适合放置在1个子线程中,是否还需要再次创建子线程,都是需要考虑的。在while 中放置一个QCoreApplication::processEvents();来人为触发事件。可以在一些场景下,保证while循环运行同时,响应其他所有事件,但是其后也要跟一个sleep指令,并且时间要合适,才能保证其他事件的及时响应。个人建议不要小于10ms的sleep时间。

当循环时间小于槽函数时间时: 

#include <QtCore/QCoreApplication>
#include <QTimer>
#include <QThread>
#include <iostream>
#include <QObject>
#include <QTime>void timer1()
{std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  1" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  2" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  3" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  4" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  5" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  6" << std::endl;
}int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);QTimer timeTest;timeTest.setTimerType(Qt::PreciseTimer);QObject::connect(&timeTest, &QTimer::timeout, [=]() {timer1(); });timeTest.start(100);return a.exec();
}

执行结果: 

结果分析:

QTimer 设置的循环时间小于槽函数的执行时间时,当循环时间结束时,并不会将槽函数中断,而是等槽函数运行结束后,直接再次进入,中间没有间隔时间。

当循环间隔时间大于槽函数时间时:

#include <QtCore/QCoreApplication>
#include <QTimer>
#include <QThread>
#include <iostream>
#include <QObject>
#include <QTime>void timer1()
{std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  1" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  2" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  3" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  4" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  5" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  6" << std::endl;
}int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);QTimer timeTest;timeTest.setTimerType(Qt::PreciseTimer);QObject::connect(&timeTest, &QTimer::timeout, [=]() {timer1(); });timeTest.start(7000);return a.exec();
}

 结果分析:

间隔时间都比较准。每次的间隔时间也不会存在累计误差。

当存在两个定时器器,其中一个还是间隔100ms,另一个间隔1000ms: 

#include <QtCore/QCoreApplication>
#include <QTimer>
#include <QThread>
#include <iostream>
#include <QObject>
#include <QTime>void timer1()
{std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  1" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  2" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  3" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  4" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  5" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  6" << std::endl;
}void timer2()
{std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  Timer2" << std::endl;//QThread::msleep(1000);
}
int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);QTimer timeTest,timeTest2;timeTest.setTimerType(Qt::PreciseTimer);timeTest2.setTimerType(Qt::PreciseTimer);QObject::connect(&timeTest, &QTimer::timeout, [=]() {timer1(); });QObject::connect(&timeTest2, &QTimer::timeout, [=]() {timer2(); });timeTest.start(100);timeTest2.start(1000);return a.exec();
}

结果分析:

第一个100ms的定时器优先抢占触发事件,当执行完两个对应槽函数后,第二个1000ms的定时器才执行一次槽函数。 

100ms触发

1s-2s-3s-4s-5s-6s-1s-2s-3s-4s-5s-6s-第二个触发-

总结:在不能确定定时器槽函数执行时间时,如果还存在其他定时器,当第一个定时器执行超时时,将直接影响第二个定时器的执行周期。所以在这种应用中,尽量避免定时器的循环周期小于槽函数执行时长。

当两个定时器的循环周期大于槽函数执行时间时

#include <QtCore/QCoreApplication>
#include <QTimer>
#include <QThread>
#include <iostream>
#include <QObject>
#include <QTime>void timer1()
{std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  1" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  2" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  3" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  4" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  5" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  6" << std::endl;
}void timer2()
{std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  Timer2" << std::endl;//QThread::msleep(1000);
}
int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);QTimer timeTest,timeTest2;timeTest.setTimerType(Qt::PreciseTimer);timeTest2.setTimerType(Qt::PreciseTimer);QObject::connect(&timeTest, &QTimer::timeout, [=]() {timer1(); });QObject::connect(&timeTest2, &QTimer::timeout, [=]() {timer2(); });timeTest2.start(1000);timeTest.start(7000);return a.exec();
}

结果分析:

当两个定时器在同一个线程中时,两个定时器是按单线程串行的方式执行,当其中一个定时器触发时,必须等待当前定时器执行完成后,才有可能执行另外的定时器,两个定时器的优先级感觉是随机的。这也就解释了为什么上个案例定时周期不稳定的原因。

当在主程序中添加一个for循环后 

#include <QtCore/QCoreApplication>
#include <QTimer>
#include <QThread>
#include <iostream>
#include <QObject>
#include <QTime>void timer1()
{std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  1" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  2" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  3" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  4" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  5" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  6" << std::endl;
}void timer2()
{std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  Timer2" << std::endl;//QThread::msleep(1000);
}
int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);QTimer timeTest,timeTest2;timeTest.setTimerType(Qt::PreciseTimer);timeTest2.setTimerType(Qt::PreciseTimer);QObject::connect(&timeTest, &QTimer::timeout, [=]() {timer1(); });QObject::connect(&timeTest2, &QTimer::timeout, [=]() {timer2(); });timeTest2.start(1000);timeTest.start(7000);for (int i=0;i<100;++i){std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  Main"<<i << std::endl;QThread::msleep(100);}return a.exec();
}

结论:两个定时器必须在for循环执行完成后,才能触发。再次 证明定时器在主线程中是以串行的方式执行。 当for循环没有结束时,定时器的timeout信号在线程中是阻塞的状况,是无法响应对应槽函数的。

当在for循环中加上人为触发其他事件QCoreApplication::processEvents() 后

#include <QtCore/QCoreApplication>
#include <QTimer>
#include <QThread>
#include <iostream>
#include <QObject>
#include <QTime>void timer1()
{std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  1" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  2" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  3" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  4" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  5" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  6" << std::endl;
}void timer2()
{std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  Timer2" << std::endl;//QThread::msleep(1000);
}
int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);QTimer timeTest,timeTest2;timeTest.setTimerType(Qt::PreciseTimer);timeTest2.setTimerType(Qt::PreciseTimer);QObject::connect(&timeTest, &QTimer::timeout, [=]() {timer1(); });QObject::connect(&timeTest2, &QTimer::timeout, [=]() {timer2(); });timeTest2.start(1000);timeTest.start(7000);for (int i=0;i<100;++i){std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  Main"<<i << std::endl;//适当的位置,插入一个processEvents,保证事件循环被处理QCoreApplication::processEvents();QThread::msleep(100);}return a.exec();
}

结论:当添加了 QCoreApplication::processEvents();后 在每次的for循环中都触发一次进程事件,保证timeout事件触发,是可行的。

当把for循环放到子线程中运行时 

#include <QtCore/QCoreApplication>
#include <QTimer>
#include <QThread>
#include <iostream>
#include <QObject>
#include <QTime>void timer1()
{std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  1" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  2" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  3" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  4" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  5" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  6" << std::endl;
}void timer2()
{std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  Timer2" << std::endl;//QThread::msleep(1000);
}class TestThread1:public QThread
{//Q_OBJECT
public:TestThread1() {};~TestThread1() {};void run(){for (int i=0;i<1000;++i){std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  subThread"<<i << std::endl;//适当的位置,插入一个processEvents,保证事件循环被处理//QCoreApplication::processEvents();QThread::msleep(100);}}};int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);QTimer timeTest,timeTest2;timeTest.setTimerType(Qt::PreciseTimer);timeTest2.setTimerType(Qt::PreciseTimer);QObject::connect(&timeTest, &QTimer::timeout, [=]() {timer1(); });QObject::connect(&timeTest2, &QTimer::timeout, [=]() {timer2(); });timeTest2.start(1000);timeTest.start(7000);TestThread1* test1{nullptr};test1 = new TestThread1;test1->start();//  for (int i=0;i<100;++i)//  {//      std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  Main"<<i << std::endl;适当的位置,插入一个processEvents,保证事件循环被处理//QCoreApplication::processEvents();//      QThread::msleep(100);//  }return a.exec();
}

 结论:当在子线程中运行时,两个定时器能正常按预想的方式运行

当在子线程中定义定时器时 

#include <QtCore/QCoreApplication>
#include <QTimer>
#include <QThread>
#include <iostream>
#include <QObject>
#include <QTime>void timer1()
{std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  1" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  2" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  3" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  4" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  5" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() <<"  6" << std::endl;
}void timer2()
{std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  Timer2" << std::endl;//QThread::msleep(1000);
}void timer3()
{std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  subThreadTime3_1" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  subThreadTime3_2" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  subThreadTime3_3" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  subThreadTime3_4" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  subThreadTime3_5" << std::endl;QThread::msleep(1000);std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  subThreadTime3_6" << std::endl;
}void timer4()
{std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  subThreadTimer4" << std::endl;//QThread::msleep(1000);
}class TestThread1:public QThread
{//Q_OBJECT
public:TestThread1() {};~TestThread1() {};void run(){QTimer time3;QTimer time4;time3.setTimerType(Qt::PreciseTimer);time4.setTimerType(Qt::PreciseTimer);QObject::connect(&time3, &QTimer::timeout, [=]() {timer3(); });QObject::connect(&time4, &QTimer::timeout, [=]() {timer4(); });time3.start(1000);time4.start(7000);for (int i=0;i<1000;++i){std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  subThread"<<i << std::endl;//适当的位置,插入一个processEvents,保证事件循环被处理QCoreApplication::processEvents();QThread::msleep(100);}}};int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);QTimer timeTest,timeTest2;timeTest.setTimerType(Qt::PreciseTimer);timeTest2.setTimerType(Qt::PreciseTimer);QObject::connect(&timeTest, &QTimer::timeout, [=]() {timer1(); });QObject::connect(&timeTest2, &QTimer::timeout, [=]() {timer2(); });timeTest2.start(1000);timeTest.start(7000);TestThread1* test1{nullptr};test1 = new TestThread1;test1->start();//  for (int i=0;i<100;++i)//  {//      std::cout << QTime::currentTime().toString("HH:mm:ss zzz").toStdString() << "  Main"<<i << std::endl;适当的位置,插入一个processEvents,保证事件循环被处理//QCoreApplication::processEvents();//      QThread::msleep(100);//  }return a.exec();
}

结论:当在子线程中定义定时器时,现象跟在主线程的现象一致。 

QCoreApplication::processEvents();
          QThread::msleep(100); 这暂停很关键,不同的暂停时间,对其他事件的影响很大,如果没有这个暂停时间,:processEvents()将无效,暂停时间越短,其他事件执行的几率就越小。在实际的应用中需要是个合适的延时。

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

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

相关文章

js - 对forEach()函数的一些理解

1&#xff0c;定义和用法 定义&#xff1a; forEach() 方法用于调用数组的每个元素&#xff0c;并将元素传递给回调函数。注意: forEach() 对于空数组是不会执行回调函数的。 用法&#xff1a; // 箭头函数 forEach((element) > { /* … */ }) forEach((element, index) &…

mcu 启动流程

MCU启动流程 MCU启动流程 MCU启动流程1 MCU的启动方式2 MCU程序启动执行过程3 启动过程的执行工作4 keil调式过程验证5 调试文件map 1 MCU的启动方式 单片机的启动方式&#xff0c;以stm32为例&#xff0c;如下&#xff1a; 不同的下载方式对应的不同的启动方式&#xff0c;st…

truffle 进行智能合约测试

本方法使用了可视化软件Ganache 前两步与不使用可视化工具的步骤是一样的&#xff08;有道云笔记&#xff09;&#xff0c;到第三步的时候需要注意&#xff1a; 在truffle插件下找到networks目录&#xff0c;提前打开Ganache软件 在Ganache中选择连接或者新建&#xff0c;我在…

如何学习Java集合框架? - 易智编译EaseEditing

要学习Java集合框架相关的技术和知识&#xff0c;可以按照以下步骤进行&#xff1a; 掌握Java基础知识&#xff1a; 在学习集合框架之前&#xff0c;确保你已经具备良好的Java编程基础&#xff0c;包括语法、面向对象编程&#xff08;OOP&#xff09;原理和常用的核心类库等。…

MySQL备份与还原/索引/视图

MySQL备份与还原/索引/视图练习 文章目录 一、备份与还原1、使用mysqldump命令备份数据库中的所有表2、备份booksDB数据库中的books表3、使用mysqldump备份booksDB和test数据库4、使用mysqldump备份服务器中的所有数据库5、使用mysql命令还原第二题导出的book表6、进入数据库使…

STM32案例学习 GY-39环境监测传感器模块

STM32案例学习 GY-39环境监测传感器模块 硬件平台 野火STM32F1系列开发板正点STM32F1系列开发板STM32F103ZET6核心板GY-39环境监测传感器模块 GY-39环境监测传感器模块 GY-39 是一款低成本&#xff0c;气压&#xff0c;温湿度&#xff0c;光强度传感器模块。工作电压 3-5v…

thinkphp 上传图片

public function upload_img(){// 读取图片资源// 存储路径$path "uploads/avatar";$file request()->file(background_img);// 存储图片$info $file->rule(uniqid)->move($path);// 存储成功if ($info) {//获取到上传图片的路径名称$name_img $path . …

linux查看ipynb文件

linux查看ipynb文件 使用jupyter查看 使用jupyter查看 安装 pip install jupyter添加配置好的环境到jupyter notebook的kernel中&#xff1a; python -m ipykernel install --user --name mmdet --display-name "mmdet"运行jupyter notebook &#xff08;在ipynb…

WebSocket理论和实战

一 WebSocket理论 1.1 什么是http请求 http链接分为短链接、长链接&#xff0c;短链接是每次请求都要三次握手才能发送自己的信息。即每一个request对应一个response。长链接是在一定的期限内保持链接&#xff08;但是是单向的&#xff0c;只能从客户端向服务端发消息&#x…

pycharm import的类库修改后要重启问题的解决方法

通过将以下行添加到pycharm中的settings-> Build,Excecution,Deployment-> Console-> Python Console中&#xff0c;可以指示Pycharm在更改时自动重新加载模块&#xff1a; %load_ext autoreload %autoreload 2

ubuntu 设置系统时间矫正

1、安装ntpdate&#xff0c;同步标准时间 2、修改时区 3、在.profile文件中写入上面提示的信息&#xff0c;保存退出、更新配置文件或者重启生效 3.1、或者配合上面的cp那条命令&#xff0c;用下面的命令保存到底层 $ hwclock --systohc 4、重启之后&#xff0c;查看日期时间已…

中间件上云部署 rocketmq

中间件上云部署 rocketmq rocketmq部署一、rokectmq介绍二、rokectmq特性三、使用rocketmq理由四、rocketmq 核心概念五、rocketmq角色六、rocketmq集群部署方式七、rocketmq集群部署7.1 环境说明7.2 构建rocketmq镜像7.3 获取rocketmq-dashboard镜像7.4 rocketmq部署描述文件编…

linux安装mysql以及使用navicat连接mysql

目录 一、下载mysql 二、安装mysql 三、使用Navicat连接MySQL 四、常见问题 1、启动服务时报错 Failed to start mysql.service: Unit not found. 的解决方法。 2、登录过程出现&#xff1a;access denied for user’root’‘localhost’(using password:Yes) 的解决方…

Redis的缓存问题

说起Redis的缓存&#xff0c;我们知道前端发出的请求到后端&#xff0c;后端先从Redis中查询&#xff0c;如果查询到了则直接返回&#xff0c;如果Redis中未查询到&#xff0c;就去数据库中查询&#xff0c;如果数据库中存在&#xff0c;则返回结果并且更新到Redis缓存当中&…

《遗留系统现代化》读书笔记(基础篇)

目录 为什么要对遗留系统进行现代化&#xff1f; 什么是遗留系统&#xff1f; 遗留系统的现代化价值 总结 遗留系统的四化建设 代码现代化 架构现代化 DevOps 现代化 团队结构现代化 总结 本文地址&#xff1a;《遗留系统现代化》读书笔记&#xff08;基础篇&#xff…

通讯录(纯C语言实现)

相信大家都有过通讯录&#xff0c;今天我来带大家实现以下最简单的通讯录&#xff0c;通过本篇文章&#xff0c;相信可以让大家对C语言有进一步的认识。 话不多说&#xff0c;我们先放函数的实现 #define _CRT_SECURE_NO_WARNINGS 1 #include "Contact.h"int Chea…

高时空分辨率、高精度一体化预测技术之风、光、水能源自动化预测教程

详情点击链接&#xff1a;高时空分辨率、高精度一体化预测技术之风、光、水能源自动化预测 第一&#xff1a;预测平台及安装 一、高精度气象预测基础 综合气象观测数值模拟模式&#xff1b; 全球预测模式、中尺度数值模式&#xff1b; 二、自动化预测平台 Linux系统 Crontab…

记一次rabbitmq消息发送成功,消费丢失问题

记一次rabbitmq消息发送成功&#xff0c;消费丢失问题 背景 测试数据归档&#xff0c;偶现数据未归档 排查 idea线上调试&#xff0c;log日志&#xff0c;数据库消息发送记录&#xff0c;代码分块重复执行看哪块出的问题&#xff0c;结果均无问题&#xff0c;最后使用rabbi…

AI销售工具:驱动销售团队效率和个性化服务的未来

在数字化时代&#xff0c;AI销售工具成为推动销售行业发展的重要力量。这些创新工具融合了人工智能技术和销售流程&#xff0c;以提高销售团队的效率和提供个性化服务为目标。随着科技的不断进步&#xff0c;AI销售工具正引领着销售行业走向一个更加智能和高效的未来。 AI驱动的…

数据结构 ~ 栈、队列

栈 一个后进先出的数据结构、JS中没有栈&#xff0c;可以使用 Array 模拟 const stack [] stack.push(1) // 入栈 stack.push(2) // 入栈 const item1 stack.pop() // 出栈 const item2 stack.pop() // 出栈以上代码可以使用 nodeJs 断点调试&#xff08;F5启动&#xff0…