当前位置: 首页 > news >正文

宁波北仑网站建设/网址查询

宁波北仑网站建设,网址查询,长沙网络营销已成趋势,百度入口网页版引用 Qt多线程中使用QTimer(常见问题汇总) [多线程]多线程使用QTimer Qt::ConnectionType:Qt不同类型connect的详细区别说明与应用 Qt的4种多线程实现方式 一文搞定之Qt多线程(QThread、moveToThread) QTimer The QTimer class provides repe…

引用

Qt多线程中使用QTimer(常见问题汇总)

[多线程]多线程使用QTimer

Qt::ConnectionType:Qt不同类型connect的详细区别说明与应用

Qt的4种多线程实现方式

一文搞定之Qt多线程(QThread、moveToThread)

QTimer

The QTimer class provides repetitive and single-shot timers.

The QTimer class provides a high-level programming interface for timers. To use it, create a QTimer, connect its timeout() signal to the appropriate slots, and call start(). From then on, it will emit the timeout() signal at constant intervals.

使用QTimer类定义一个定时器,它可以不停重复,也可以只进行一次便停止

QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
timer->start(1000);

创建一个QTimer对象,将信号timeout()与相应的槽函数相连,然后调用start()函数。接下来,每隔一段时间,定时器便会发出一次timeout()信号

Qt多线程的实现

QThread::run()

QThread 是 Qt 中实现多线程的基础类,通过继承 QThread 类并重写其 run() 函数可以实现自定义线程逻辑

  • 线程类
#ifndef WORKER_H
#define WORKER_H#include <QThread>class Worker : public QThread
{
public:Worker();void run();void printFunc();};#endif // WORKER_H
#include "Worker.h"
#include <QDebug>Worker::Worker()
{}void Worker::run()
{qDebug()<<"子线程ThreadID: "<<QThread::currentThreadId();
}void Worker::printFunc()
{qDebug()<<"子线程成员函数ThreadID: "<<QThread::currentThreadId();
}
  • main函数
#include <iostream>
#include <QDebug>
#include "Worker.h"using namespace std;int main()
{Worker w;w.start();qDebug()<<"主线程ThreadID: "<<QThread::currentThreadId();w.printFunc();while (1){}return 0;
}
  • 执行结果
子线程ThreadID: 0x4138
主线程ThreadID: 0x34b0
子线程成员函数ThreadID: 0x34b0

主线程和子线程执行的顺序不确定,偶尔主线程在前,偶尔子线程在前

子线程类的成员函数包括槽函数是运行在主线程当中的,只有run()函数运行在子线程中

如果在run()函数中调用子线程类成员函数,那么该成员函数运行在子线程中

  • 在run()函数中调用子线程成员函数
#include "Worker.h"
#include <QDebug>Worker::Worker()
{}void Worker::run()
{qDebug()<<"子线程ThreadID: "<<QThread::currentThreadId();printFunc();
}void Worker::printFunc()
{qDebug()<<"子线程成员函数ThreadID: "<<QThread::currentThreadId();
//    emit doTask();
}
主线程ThreadID: 0x2140
子线程ThreadID: 0x2044
子线程成员函数ThreadID: 0x2044

QThread::moveToThread()

moveToThread() 是 Qt 中用于将对象移动到另一个线程的方法。通过调用 moveToThread() 函数,可以将一个 QObject 对象从当前线程移动到另一个线程中,从而实现对象在新线程中执行特定的任务

在多线程编程中,通常会使用 moveToThread() 方法来将耗时的任务或需要在单独线程中执行的逻辑移动到单独的线程中,以避免阻塞主线程(通常是 GUI 线程)的执行

  • 线程类
#ifndef WORKER_H
#define WORKER_H#include <QObject>class Worker : public QObject
{Q_OBJECT
public:Worker();void printFunc();public slots:void doWork();void doWork2();void doWork3();signals:void testdoWork3();};#endif // WORKER_H
#include "Worker.h"
#include <QDebug>
#include <QThread>Worker::Worker()
{}void Worker::printFunc()
{qDebug() << "成员函数ThreadID:"<<QThread::currentThreadId();}void Worker::doWork()
{qDebug() << "doWork ThreadID:"<<QThread::currentThreadId();
}void Worker::doWork2()
{qDebug() << "doWork2 ThreadID:"<<QThread::currentThreadId();
}void Worker::doWork3()
{qDebug() << "doWork3 ThreadID:"<<QThread::currentThreadId();
}
  • main函数
#include "mainwindow.h"#include <QApplication>
#include "Worker.h"
#include <QDebug>
#include <QThread>int main(int argc, char *argv[]) {QApplication a(argc, argv);//MainWindow w;//w.show();Worker worker;QThread thread;worker.moveToThread(&thread);QObject::connect(&thread, &QThread::started, &worker, &Worker::doWork);         //第一槽函数QObject::connect(&thread, &QThread::started, &worker, &Worker::doWork2);        //第二槽函数QObject::connect(&worker, &Worker::testdoWork3, &worker, &Worker::doWork3);     //第三槽函数//启动线程thread.start();//调用成员数worker.printFunc();//发送自定义信号emit worker.testdoWork3();while (1) {}return a.exec();
}
  • 执行结果
成员函数ThreadID: 0x1330
doWork ThreadID: 0x4070
doWork2 ThreadID: 0x4070
doWork3 ThreadID: 0x4070

槽函数无论是线程的信号触发还是自定义信号触发,槽函数都在新线程里运行

成员函数和主函数运行在主线程当中

QtConcurrent::run()

QtConcurrent::run 是 Qt 库中的一个用于并行执行任务的函数。它允许你在一个独立的线程中运行一个函数,而无需显式地创建和管理线程。这是通过将函数和其参数传递给 QtConcurrent::run 来实现的,Qt 会自动管理线程池和线程的生命周期

QtConcurrent::run能够方便快捷的将任务丢到子线程中去执行,无需继承任何类,也不需要重写函数,使用非常简单。需要注意的是,由于该线程取自全局线程池QThreadPool,函数不能立马执行,需要等待线程可用时才会运行

使用QtConcurrent::run()的基本步骤:

  • 传递一个函数或可调用对象(例如 lambda、函数指针、成员函数等)给 QtConcurrent::run
  • QtConcurrent::run 会在后台线程中执行该函数,并返回一个 QFuture 对象,表示异步操作的结果
  • 可以通过 QFuture 来监控任务的进度和结果

基本语法

QFuture<TResult> QtConcurrent::run(Func func, Args... args);
  • func:要执行的函数或可调用对象
  • args:传递给函数的参数
#include <QCoreApplication>
#include <QtConcurrent>
#include <QDebug>
#include <QThread>
#include <QFuture>void slowFunction(int seconds) {qDebug() << "Start slow function in thread:" << QThread::currentThreadId();QThread::sleep(seconds);  // 模拟耗时操作qDebug() << "Finished slow function";
}int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);// 在后台线程执行 slowFunctionQFuture<void> future = QtConcurrent::run(slowFunction, 5); // 传入参数 5 表示等待 5 秒// 在此可以执行其他操作,不会被阻塞qDebug() << "Main thread doing something else...";// 等待后台任务完成future.waitForFinished();return a.exec();
}
  • QtConcurrent::run(slowFunction, 5) 会在后台线程中运行 slowFunction,并传递参数 5,该函数会使线程等待 5 秒钟
  • 在此过程中,主线程可以继续执行其他任务,比如打印 “Main thread doing something else…”。
  • future.waitForFinished() 会阻塞主线程直到后台任务完成

如果任务有返回值,可以通过 QFuture::result() 获取

#include <QCoreApplication>
#include <QtConcurrent>
#include <QDebug>
#include <QFuture>int computeSum(int a, int b) {qDebug() << "Computing sum in background thread...";QThread::sleep(2);  // 模拟耗时操作return a + b;
}int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);// 在后台线程中执行带有返回值的任务QFuture<int> future = QtConcurrent::run(computeSum, 5, 10);// 在此可以继续执行其他任务qDebug() << "Main thread is free to do other work";// 获取任务的结果int result = future.result();  // 阻塞直到任务完成qDebug() << "The result of computation is:" << result;return a.exec();
}

如果需要在任务完成后处理结果,可以使用 QFuture::watch() 或者 QFutureWatcher 来接收通知

QtConcurrent::run 是一个简单的 API,它依赖于 Qt 的线程池来管理线程,因此它适合处理不需要显式控制线程的简单任务

总结

moveToThread对比传统子类化Qthread更灵活,仅需要把你想要执行的代码放到槽,movetothread这个object到线程,然后拿一个信号连接到这个槽就可以让这个槽函数在线程里执行。可以说,movetothread给我们编写代码提供了新的思路,当然不是说子类化QThread不好,只是你应该知道还有这种方式去调用线程

轻量级的函数可以用movethread,多个短小精悍能返回快速的线程函数适用 ,无需创建独立线程类,例如你有20个小函数要在线程内做, 全部扔给一个QThread。而我觉得movetothread和子类化QThread的区别不大,更可能是使用习惯引导。又或者你一开始没使用线程,但是后边发觉这些代码还是放线程比较好,如果用子类化QThread的方法重新设计代码,将会有可能让你把这一段推到重来,这个时候,moveThread的好处就来了,你可以把这段代码的从属着movetothread,把代码移到槽函数,用信号触发它就行了。其它的话movetothread它的效果和子类化QThread的效果是一样的,槽就相当于你的run()函数,你往run()里塞什么代码,就可以往槽里塞什么代码,子类化QThread的线程只可以有一个入口就是run(),而movetothread就有很多触发的入口

以下是一些常用的QThread函数:

  • start(): 启动线程,使线程进入运行状态,调用线程的run()方法
  • run(): 线程的执行函数,需要在该函数中编写线程所需执行的任务
  • quit(): 终止线程的事件循环,在下一个事件处理周期结束时退出线程
  • wait(): 阻塞当前线程,直到线程执行完成或超时
  • finished(): 在线程执行完成时发出信号
  • terminate(): 强制终止线程的执行,不推荐使用,可能导致资源泄漏和未定义行为
  • isRunning(): 判断线程是否正在运行
  • currentThreadId(): 返回当前线程的ID
  • yieldCurrentThread(): 释放当前线程的时间片,允许其他线程执行
  • setPriority(): 设置线程优先级
  • msleep(): 让当前线程休眠指定的毫秒数

函数使用时的注意事项

  • start()函数: 调用start()函数启动线程时,会自动调用线程对象的run()方法。不要直接调用run()方法来启动线程,应该使用start()函数
  • wait()函数: wait()函数会阻塞当前线程,直到线程执行完成。在调用wait()函数时需要确保不会发生死锁的情况,避免主线程和子线程相互等待对方执行完成而无法继续
  • terminate()函数: 调用terminate()函数会强制终止线程,这样可能会导致资源未能正确释放,造成内存泄漏等问题。因此应该尽量避免使用terminate()函数,而是通过设置标志让线程自行退出
  • quit()函数: quit()函数用于终止线程的事件循环,通常与exec()函数一起使用。在需要结束线程事件循环时,可以调用quit()函数
  • finished信号: 当线程执行完成时会发出finished信号,可以连接这个信号来处理线程执行完成后的操作
  • yieldCurrentThread()函数: yieldCurrentThread()函数用于让当前线程让出时间片,让其他线程有机会执行。使用时应该注意避免过多的调用,否则会影响程序性能

多线程中的QTimer

错误用法

错误用法1

子类化QThread,在线程类中定义一个定时器,然后在run()方法中调用定时器的start()方法

TestThread::TestThread(QObject *parent): QThread(parent)
{m_pTimer = new QTimer(this);connect(m_pTimer, &QTimer::timeout, this, &TestThread::timeoutSlot);
}void TestThread::run()
{m_pTimer->start(1000);
}void TestThread::timeoutSlot()
{qDebug() << QString::fromLocal8Bit("当前线程id:") << QThread::currentThread();
}

接下来在主线程中创建该线程对象,并调用它的start()方法

m_pThread = new TestThread(this);
m_pThread->start();

执行时会报错,定时器不能被其它线程start

QObject::startTimer: Timers cannot be started from another thread

分析一下:

  • 刚开始只有主线程一个,TestThread的实例是在主线程中创建的,定时器在TestThread的构造函数中,所以也是在主线程中创建的
  • 当调用TestThread的start()方法时,这时有两个线程。定时器的start()方法是在另一个线程中,也就是TestThread中调用的

💡 创建和调用并不是在同一线程中,所以出现了错误

每个QObject实例都有一个叫做“线程关系”(thread affinity)的属性,或者说,它处于某个线程中。默认情况下,QObject处于创建它的线程中。
当QObject接收队列信号(queued signal)或者传来的事件(posted event),槽函数或事件处理器将在对象所处的线程中执行。
根据以上的原理,Qt使用计时器的线程关系(thread affinity)来决定由哪个线程发出timeout()信号。正因如此,你必须在它所处的线程中start或stop该定时器,在其它线程中启动定时器是不可能的。

错误用法2

OK,看完错误1,那是不是在run函数里面构造定时器就可以了,构造也要小心喔,别一不小心指定了父类,如下

void MyThread::run()
{timer = new QTimer(this);connect(timer,SIGNAL(timeout()),this,SLOT(timerOut()));timer->start(1000);exec();
}

执行时报错

QObject: Cannot create children for a parent that is in a different thread.
(Parent is TestThread(0x709d88), parent’s thread is QThread(0x6e8be8), current thread is TestThread(0x709d88)

因为TestThread对象是在主线程中创建的,它的QObject子对象也必须在主线程中创建。所以不能指定父对象为TestThread

错误用法3

这个问题也很容易犯,即计时器虽在线程中初始化,但在子线程非run()函数中开始start()

void MyThread::run()
{timer = new QTimer();connect(timer,SIGNAL(timeout()),this,SLOT(timerOut()));startTimer();exec();
}void MyThread::startTimer(){qDebug()<<"当前线程ID:"<<QThread::currentThreadId();timer->start(1000);
}void MyThread::timerOut()
{qDebug()<<"当前线程ID:"<<QThread::currentThreadId();
}

执行输出

前线程ID: 0x4338
当前线程ID: 0x3e20
当前线程ID: 0x3e20

run()函数线程为子线程,因此run函数中运行startTimer()为run所处线程,但因为startTimer()初始化时为主线程,因此timer->start()也随之在主线程中开始,计时器槽函数也在主线程中运行

正确用法

正确用法1

void MyThread::run()
{timer = new QTimer();connect(timer,SIGNAL(timeout()),this,SLOT(timerOut()));timer->start(1000);exec();
}void MyThread::timerOut()
{qDebug()<<"当前线程ID:"<<QThread::currentThreadId();
}

执行输出

主线程ID: 0x4458
当前线程ID: 0x4094
当前线程ID: 0x4094
当前线程ID: 0x4094

正确用法2

无需子类化线程类,通过信号启动定时器

TestClass::TestClass(QWidget *parent): QWidget(parent)
{m_pThread = new QThread(this);m_pTimer = new QTimer();m_pTimer->moveToThread(m_pThread);m_pTimer->setInterval(1000);connect(m_pThread, SIGNAL(started()), m_pTimer, SLOT(start()));connect(m_pTimer, &QTimer::timeout, this, &ThreadTest::timeOutSlot, Qt::DirectConnection);
}

通过moveToThread()方法改变定时器所处的线程,不要给定时器设置父类,否则该函数将不会生效

首先将定时器所处的线程改为新建的线程,然后连接信号槽,槽函数在定时器所处的线程中执行,注意信号槽的连接类型为Qt::DirectConnection

正确用法3

如果不想在run()函数中就开始计时器,而是在线程运行过程中根据实际情况开启(之前错误3的情况)时要怎么办呢

解决办法为:信号与槽连接中使用Qt::*DirectConnection*

信号与槽连接默认方式为:Qt::AutoConnection,因此会根据函数所处的线程自动跳转,导致错误3中的情况

void MyThread::run()
{timer = new QTimer();connect(timer,SIGNAL(timeout()),this,SLOT(timerOut()),Qt::DirectConnection);startTimer();exec();
}void MyThread::startTimer(){qDebug()<<"当前线程ID:"<<QThread::currentThreadId();timer->start(1000);
}void MyThread::timerOut()
{qDebug()<<"当前线程ID:"<<QThread::currentThreadId();
}

执行输出

主线程ID: 0x4424
当前线程ID: 0x470c
当前线程ID: 0x470c
当前线程ID: 0x470c
当前线程ID: 0x470c

Qt::ConnectionType

从上面的内容可以看到又引申出了多线程中槽函数在哪个线程中执行的问题,这里再补充说明下

同一对象的不同槽函数可以有不同的连接类型,槽函数在哪个线程被执行由连接类型、信号发射时收发双方是否在一个线程决定

类型说明

Qt::AutoConnection

默认连接类型,如果信号接收方与发送方在同一个线程,则使用Qt::DirectConnection,否则使用Qt::QueuedConnection;连接类型在信号发射时决定

Qt::DirectConnection

信号所连接至的槽函数将会被立即执行,并且是在发射信号的线程;倘若槽函数执行的是耗时操作、信号由UI线程发射,则会阻塞Qt的事件循环,UI会进入无响应状态

Qt::QueuedConnection

槽函数将会在接收者的线程被执行,此种连接类型下的信号倘若被多次触发、相应的槽函数会在接收者的线程里被顺次执行相应次数;当使用QueuedConnection时,参数类型必须是Qt基本类型,或者使用qRegisterMetaType() 进行注册了的自定义类型

Qt::BlockingQueuedConnection

和Qt::QueuedConnection类似,区别在于发送信号的线程在槽函数执行完毕之前一直处于阻塞状态;收发双方必须不在同一线程,否则会导致死锁

Qt::UniqueConnection

可以搭配以上所有连接类型使用,一经设置之后,同一信号与同一槽函数的二次连接将会失败

测试验证

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QThread>
#include <QPushButton>
#include <windows.h>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass ThreadWorker : public QObject
{Q_OBJECT
public:ThreadWorker(QObject* parent);public slots:void queuedConnect();void directConnect();
};class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private:QVector<QThread*> listThread;QVector<ThreadWorker*> listWorker;Ui::Widget *ui;private slots:void on_butDirect_clicked();void on_butQueued_clicked();void on_butAuto_clicked();signals:void directConnect();void autoConnect();void queuedConnect();};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);for(int i = 0 ; i < 3 ; i++){listThread.append(new QThread(this));listWorker.append(new ThreadWorker(nullptr));}connect(this,SIGNAL(directConnect()),listWorker[0],SLOT(directConnect()),Qt::DirectConnection);connect(this,SIGNAL(autoConnect()),listWorker[2],SLOT(directConnect()),Qt::AutoConnection);connect(this,SIGNAL(queuedConnect()),listWorker[1],SLOT(queuedConnect()),Qt::QueuedConnection);connect(this,SIGNAL(directConnect()),listWorker[1],SLOT(directConnect()),Qt::QueuedConnection);for(int  i = 0 ; i < 3 ; i++ )listWorker[i]->moveToThread(listThread[i]);for(auto i : listThread) i->start();qDebug()<<"The main thread id is "<< QThread::currentThreadId();}Widget::~Widget()
{delete ui;for(auto i : listThread)i->exit();
}void Widget::on_butDirect_clicked()
{emit directConnect();
}void Widget::on_butQueued_clicked()
{emit queuedConnect();
}void Widget::on_butAuto_clicked()
{emit autoConnect();}ThreadWorker::ThreadWorker(QObject *parent) : QObject(parent)
{}void ThreadWorker::queuedConnect()
{for(int i  = 0 ; i <10 ; i ++)Sleep(100);qDebug()<<"The kid thread id is "<< QThread::currentThreadId();}
void ThreadWorker::directConnect()
{for(int i  = 0 ; i <10 ; i ++)Sleep(100);qDebug()<<"The kid thread id is "<< QThread::currentThreadId();}

执行输出

The main thread id is  0x30b0
The kid thread id is  0x30b0
The kid thread id is  0x7cc
The kid thread id is  0x7cc
The kid thread id is  0x24c0

小结

这里参考学习了多篇博客,对Qt的多线程实现,以及如何在多线程场景中使用QTimer有了更深的认识,同时对多线程中槽函数的调用也有了新的认识。希望和大家一起进步

相关文章:

Qt多线程与QTimer详解

引用 Qt多线程中使用QTimer&#xff08;常见问题汇总&#xff09; [多线程]多线程使用QTimer Qt::ConnectionType&#xff1a;Qt不同类型connect的详细区别说明与应用 Qt的4种多线程实现方式 一文搞定之Qt多线程(QThread、moveToThread) QTimer The QTimer class provides repe…...

基于stm23的智慧宿舍系统 (DAY10)_小程序

好久没记录开发进度了&#xff0c;今天小程序差不多开发完了&#xff0c;UI这块算是比较常见了&#xff0c;主要功能是能连接onenet查看设备上传的数据&#xff0c;同时也能对设备进行一些控制下面是几个主要的函数&#xff0c;功能比较简单 wx.request({url: ${apiBaseUrl}/t…...

深入理解Spring事务

目录 什么是Spring事务为什么需要Spring事务Spring事务的实现 Spring事务的传播机制Spring事务的底层原理 EnableTransactionManagement --开启Spring管理事务Import(TransactionManagementConfigurationSelector.class) --提供两个beanAutoProxyRegistrar --启用AOP的功能&am…...

Ubuntu22.04深度学习环境安装【Anaconda+Pycharm】

anaconda可以提供多个独立的虚拟环境&#xff0c;方便我们学习深度学习&#xff08;比如复现论文&#xff09;&#xff1b; Pycharm编辑器可以高效的编写python代码&#xff0c;也是一个很不错的工具。 下面就记录下Ubuntu22.04的安装流程&#xff1a; 1.Anaconda安装 下载Ana…...

五、docker的网络模式

五、docker的网络模式 5.1 Docker的四种网络模式 当你安装docker时&#xff0c;它会自动创建三个网络&#xff0c;可使用如下命令查看&#xff1a; [rootlocalhost ~]# docker network ls NETWORK ID NAME DRIVER SCOPE 7390284b02d6 bridge bridge lo…...

使用el-row和el-col混合table设计栅格化,实现表头自适应宽度,表格高度占位

演示效果&#xff1a; 如上图,由于地址信息很长,需要占多个格子,所以需要错开,若想实现这种混合效果,可以这样搭建: 页面效果&#xff1a; 代码分析: 上面使用el-row和el-col搭建表单显示 第一排三个8,第二排8和16 下面混合table实现&#xff0c;并使用border来自适应宽度…...

【服务器监控】grafana+Prometheus+node exporter详细部署文档

我们在进行测试时&#xff0c;不可能一直手动看着服务器的性能消耗&#xff0c;这时候就需要有个工具替我们监控服务器的性能消耗。这里记录下grafanaPrometheusnodeExporter的组合用于监控服务器。 简单介绍&#xff1a; grafana&#xff1a;看板工具&#xff0c;所有采集的…...

JavaScript中todolist操作--待办事项的添加 删除 完成功能

效果图 在文本框中输入内容点击添加按钮会在下面生成 添加功能 html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0&qu…...

Windows中MySQL8.3.4 MSI版本——详细安装教程

一、下载MySQL安装文件。 下载地址&#xff1a;MySQL官网 进入后点击下面的MySQL社区版下载 点击MySQL Comunity Server。 我这里选择的是版本8.4.3LTS版本&#xff0c;在线对应的msi文件。 点击No thanks,直接下载。 二、安装MySQL 2.1、双击刚刚下载好的msi文件&#xff0c;…...

MySQL-DDL之数据库操作

文章目录 一. 创建数据库1. 直接创建数据库&#xff0c;如果存在则报错2. 如果数据库不存在则创建3. 创建数据库时设置字符集4. 栗子 二. 查看数据库1. 查看数据库 三. 删除数据库1. 删除数据库 四. 使用数据库1. 使用数据库2. 查看正在使用的数据库 数据定义语言&#xff1a;简…...

Python 笔记之进程通信

当需要创建的子进程数量不多时&#xff0c;可以直接利用multiprocessing中的Process动态生成多个进程 但是如果是上百个或者上千个目标&#xff0c;手动去创建进程的工作量很大&#xff0c;此时就可以利用到Multiprocessing模块提供的Pool方法 初始化pool时&#xff0c;可以指定…...

【Transformer序列预测】Pytorch中构建Transformer对序列进行预测源代码

Python&#xff0c;Pytorch中构建Transformer进行序列预测源程序。包含所有的源代码和数据&#xff0c;程序能够一键运行。此程序是完整的Transformer&#xff0c;即使用了Encoder、Decoder和Embedding所有模块。源程序是用jupyterLab所写&#xff0c;建议分块运行。也整理了.p…...

生产者-消费者模式:多线程并发协作的经典案例

生产者-消费者模式是多线程并发编程中一个非常经典的模式&#xff0c;它通过解耦生产者和消费者的关系&#xff0c;使得两者可以独立工作&#xff0c;从而提高系统的并发性和可扩展性。本文将详细介绍生产者-消费者模式的概念、实现方式以及应用场景。 1 生产者-消费者模式概述…...

数据库-mysql(基本语句)

演示工具&#xff1a;navicat 连接&#xff1a;mydb 一.操作数据库 1.创建数据库 ①create database 数据库名称 //普通创建 ②create database if not exists 数据库名称 //创建数据库&#xff0c;判断不存在&#xff0c;再创建&#xff1a; 使用指定数据库 use 数据库…...

android12L super.img 解压缩及其挂载到ubuntu18.04

本文介绍如何在Ubuntu18.04上解压缩高通平台Android12L的super.img&#xff0c;并将其挂载到系统中查看内容。 在源码的根目录下&#xff0c;执行如下命令&#xff1a; out/host/linux-x86/bin/simg2img out/target/product/msmnile_gvmq/super.img super.img_rawmkdir super…...

flask简易版的后端服务创建接口(python)

1.pip install安装Flask和CORS 2.创建http_server.py文件,内容如下 """ ============================ 简易版的后端服务 ============================ """ from flask import Flask, request, jsonify from flask_cors import CORS app = F…...

小程序入门学习(四)之全局配置

一、 全局配置文件及常用的配置项 小程序根目录下的 app.json 文件是小程序的全局配置文件。常用的配置项如下&#xff1a; pages&#xff1a;记录当前小程序所有页面的存放路径 window&#xff1a;全局设置小程序窗口的外观 tabBar&#xff1a;设置小程序底部的 tabBar 效…...

PHP使用RabbitMQ(正常连接与开启SSL验证后的连接)

代码中包含了PHP在一般情况下使用方法和RabbitMQ开启了SSL验证后的使用方法&#xff08;我这边消费队列是使用接口请求的方式&#xff0c;每次只从中取出一条&#xff09; 安装amqp扩展 PHP使用RabbitMQ前&#xff0c;需要安装amqp扩展&#xff0c;之前文章中介绍了Windows环…...

轻量级视觉骨干网络 MobileMamba: Lightweight Multi-Receptive Visual Mamba Network

MobileMamba 快速链接解决问题&#xff1a;视觉模型在移动设备端性能和效果的平衡性解决方法&#xff1a;改进网络结构训练和测试策略网络结构改进训练和测试策略 实验支撑&#xff1a;图像分类、分割&#xff0c;目标检测等图像分类结果对比目标检测和实例分割结果对比语义分割…...

科技云报到:数智化转型风高浪急,天翼云如何助力产业踏浪而行?

科技云报到原创。 捷径消亡&#xff0c;破旧立新&#xff0c;是今年千行百业的共同底色。 穿越产业周期&#xff0c;用数字化的力量重塑企业经营与增长的逻辑&#xff0c;再次成为数字化技术应用的主旋律&#xff0c;也是下一阶段产业投资的重点。 随着数字化转型行至“深水区…...

dockerfile部署前后端(vue+springboot)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言0.环境说明和准备1.前端多环境打包1.1前端多环境设置1.2打包 2.后端项目多环境配置以及打包2.1后端多环境配置2.2项目打包 3.文件上传4.后端镜像制作4.1dockerf…...

c语言的思维导图

之前已经全部学完c语言了&#xff0c;所以为了更好的复习回顾&#xff0c;我做了一份c语言超详细的思维导图&#xff0c;帮助实现一张图就可以复习&#xff0c;避免盲目&#xff0c; 由于平台不支持直接发上图&#xff0c;有想要的小伙伴&#xff0c;可以私信找我要原件...

Android 拍照(有无存储权限两种方案,兼容Q及以上版本)

在某些行业&#xff0c;APP可能被禁止使用存储权限&#xff0c;或公司在写SDK功能&#xff0c;不方便获取权限 所以需要有 无存储权限拍照方案。这里两种方案都列出里。 对于写入权限&#xff0c;在高版本中&#xff0c;已经废弃&#xff0c; 不可用文件写入读取权限&#xf…...

MongoDB在自动化设备上的应用示例

发现MongoDB特别适合自动化检测数据的存储。。。 例如一个晶圆检测项目&#xff0c;定义其数据结构如下 #pragma once #include <vector> #include <QString> #include <QRectF> #include <string> #include <memory>class tpoWafer; class tp…...

draggable插件——实现元素的拖动排序——拖动和不可拖动的两种情况处理

最近在写后台管理系统的时候&#xff0c;遇到一个需求&#xff0c;就是关于拖动排序的功能。 我之前是写过一个关于拖动表格的功能&#xff0c;此功能可以实现表格中的每一行数据上下拖动实现排序的效果。 vue——实现表格的拖拽排序功能——技能提升 但是目前我这边的需求是…...

Redux的使用

到如今redux的已经不是react程序中必须的一部分内容了&#xff0c; 我们应该在本地需要大量更新全局变量时才使用它! redux vs reducer reducer的工作机制&#xff1a; 手动构造action对象传入dispatch函数中 dispatch函数将 action传入reducer当中 reducer结合当前state与a…...

【JAVA】Java高级:多数据源管理与Sharding:数据分片(Sharding)技术的实现与实践

大规模分布式系统&#xff0c;数据存储和管理变得越来越复杂。随着用户数量和数据量的急剧增加&#xff0c;单一数据库往往难以承载如此庞大的负载。这时&#xff0c;数据分片&#xff08;Sharding&#xff09;技术应运而生。数据分片是一种将数据水平切分到多个数据库实例的技…...

ASP.NET Core 9.0 静态资产传递优化 (MapStaticAssets )

一、结论 &#x1f4a2;先看结论吧&#xff0c; MapStaticAssets 在大多数情况下可以替换 UseStaticFiles&#xff0c;它已针对为应用在生成和发布时了解的资产提供服务进行了优化。 如果应用服务来自其他位置&#xff08;如磁盘或嵌入资源&#xff09;的资产&#xff0c;则应…...

LeetCode刷题day18——贪心

LeetCode刷题day18——贪心 135. 分发糖果分析&#xff1a; 406. 根据身高重建队列分析&#xff1a;for (auto& p : people) 昨天写了一道&#xff0c;今天写了一道&#xff0c;都有思路&#xff0c;却不能全整对。昨天和小伙伴聊天&#xff0c;说是因为最近作业多&#xf…...

MATLAB Simulink® - 智能分拣系统

系列文章目录 前言 本示例展示了如何在虚幻引擎 环境中对四种不同形状的标准 PVC 管件实施半结构化智能分拣。本示例使用 Universal Robots UR5e cobot 执行垃圾箱拣选任务&#xff0c;从而成功检测并分类物体。cobot 的末端执行器是一个吸力抓手&#xff0c;它使 cobot 能够拾…...