Qt线程高级应用

news2024/11/19 9:36:13

一般我们在用Qt开发时,把耗时操作放在线程中执行,避免卡界面,Qt的线程使用有两种方式,一种是继承QThread,一种是moveToThread的方式,以及QtConcurrent方式
首先我们来看第一种:

#ifndef WORKERTHREAD_H
#define WORKERTHREAD_H

#include <QDebug>
#include <QThread>
#include <QDateTime>

#define PRINTTIME QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss.zzz");

class WorkerThread : public QThread
{
    Q_OBJECT
public:
    explicit WorkerThread(QObject *parent = nullptr);
    int getThreadFun();

    void run() override
    {
        QString result = QString("WorkerThread");
        /* ... here is the expensive or blocking operation ... */
        QThread::sleep(3);
        qDebug() << "WorkerThread::run===============currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;
        emit resultReady(result);
    }

signals:
    void resultReady(const QString &result);

};
#endif // WORKERTHREAD_H

#include "workerthread.h"

WorkerThread::WorkerThread(QObject *parent) : QThread(parent)
{

}

int WorkerThread::getThreadFun()
{
    qDebug() << "Dialog::getThreadFun============currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;
    int id = (int)QThread::currentThreadId();
    QThread::sleep(2);
    return id;

}

 使用线程:

void Dialog::initData()
{
    m_workerThread = new WorkerThread(this);
    connect(m_workerThread, &WorkerThread::resultReady, this, &Dialog::handleResults1);
    //connect(m_workerThread, &WorkerThread::finished, m_workerThread, &Dialog::deleteLater);
    //m_workerThread->start();

    connect(ui->btn1, SIGNAL(clicked()), this, SLOT(slotBtn1()));
}


void Dialog::slotBtn1()
{
    qDebug() << "Dialog::slotBtn1================currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;
    m_workerThread->start();
    qDebug() << "Dialog::slotBtn1================currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;
    m_workerThread->getThreadFun();
}

运行结果:

 从以上信息可以看到,只有run函数里的执行是属于子线程,getThreadFun函数虽然是WorkerThread类的,但执行起来并不属于子线程,它的线程号与主线程一样,同时,开启线程后还没等结果就执行下面的语句了。run函数执行完,线程就结束了。

那么有没有一种情况,线程一直处理运行中呢?下面看第2种线程的方式:

#ifndef WORKER_H
#define WORKER_H

#include <QObject>
#include <QDebug>
#include <QThread>
#include <QDateTime>

#define PRINTTIME QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss.zzz");

class Worker : public QObject
{
    Q_OBJECT
public:
    explicit Worker(QObject *parent = nullptr);
    int getThreadFun();

public slots:
    void doWork(const QString &parameter)
    {
        QString result = QString("currentThreadId==%1").arg((int)QThread::currentThreadId());
        /* ... here is the expensive or blocking operation ... */
        QThread::sleep(3);
        qDebug() << "Worker::doWork==================currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;
        emit resultReady(result);
    }

signals:
    void resultReady(const QString &result);
};

#endif // WORKER_H
#include "worker.h"

Worker::Worker(QObject *parent)
    : QObject{parent}
{

}

int Worker::getThreadFun()
{
    qDebug() << "Worker::getThreadFun============currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;
    int id = (int)QThread::currentThreadId();
    QThread::sleep(2);
    return id;

}

使用线程:

void Dialog::initData()
{
    m_worker = new Worker;
    m_worker->moveToThread(&workerThread);
    connect(&workerThread, &QThread::finished, m_worker, &QObject::deleteLater);
    connect(this, &Dialog::operate, m_worker, &Worker::doWork);
    connect(m_worker, &Worker::resultReady, this, &Dialog::handleResults2);
    workerThread.start();

    connect(ui->btn2, SIGNAL(clicked()), this, SLOT(slotBtn2()));
}

void Dialog::slotBtn2()
{
    qDebug() << "Dialog::slotBtn2=======1========currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;
    emit operate("Worker");
    qDebug() << "Dialog::slotBtn2=======2========currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;
    m_worker->getThreadFun();
}


void Dialog::handleResults2()
{
    qDebug() << "Dialog::handleResults2==========currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;
}

运行结果:

 从上面结果也可以看出,由operate信号触发的槽函数是子线程,直接调用getThreadFun函数还是属于子线程,但这个与第一种线程的方案不同在于,线程一起处理运行中,只要触发operate信号都会执行槽函数的子线程,以上两种情况都是线程还没执行完,调用线程的函数就已经结束了。

但有时候我们需要函数的结果,并且根据结果执行不同的分支要求,那边没有一种方案可以这种做呢,下面看第3种线程方式,使用QtConcurrent获取线程执行的返回结果:

#include "dialog.h"
#include "ui_dialog.h"
#include "workerthread.h"
#include "worker.h"
#include <QDebug>
#include <QSerialPort>
#include <QtConcurrent>
#include <QTime>
#include <QDebug>
#include <QEventLoop>
#include <QtConcurrentMap>
#include <QSerialPortInfo>

using namespace QtConcurrent;

#define PRINTTIME QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss.zzz");

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::Dialog)
{
    ui->setupUi(this);
    initData();

}

Dialog::~Dialog()
{
    workerThread.quit();
    workerThread.wait();
    m_workerThread->quit();
    m_workerThread->wait();
    delete ui;
}

void Dialog::initData()
{
    connect(ui->btn3, SIGNAL(clicked()), this, SLOT(slotBtn3()));
}

int threadFun3(int a1, int a2)
{
    qDebug() << "threadFun3======================currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;
    QThread::sleep(2);
    qDebug() << "threadFun3======================currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;
    return a1 + a2;
}

void Dialog::slotBtn3()
{
    int a1 = 5092;
    int a2 = 542451;
    qDebug() << "Dialog::slotBtn3=======1========currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;
    QFuture<int> future =QtConcurrent::run(threadFun3, a1, a2);
    int result = future.result();
    qDebug() << "Dialog::slotBtn3=======2========currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;
    qDebug() << "Dialog::slotBtn3================result================" << result << PRINTTIME;
}

运行结果:

这种方案可以获取线程执行返回的结果了,但是这也存在一个问题,这个返回结果是待slotBtn3函数调用完了才返回,有时我们需要我等待这个结果再执行下面的代码。这时候就需要采用另外一种 方式下了。直接上代码:

void Dialog::initData()
{
    connect(ui->btn4, SIGNAL(clicked()), this, SLOT(slotBtn4()));
}


//这里检测串口连接设备,连上设备才算打开串口成功
QString checkDeviceConnectPort()
{
    QString openName = "";
    QString tempData{""};
    QThread::sleep(2);
    qDebug() << "checkDeviceConnectPort======================currentThreadId=====" << QThread::currentThreadId() << PRINTTIME;
    QSerialPort *serialPort = new QSerialPort();
    foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
        serialPort->setPort(info);
        if(info.portName().contains("Bluetooth", Qt::CaseInsensitive))
            continue;


        bool isOpen = serialPort->open(QIODevice::ReadWrite);
        qDebug() << "checkDeviceConnectPort(================isOpen==" << isOpen << info.portName() << PRINTTIME;
        if(isOpen)
        {
            //设置参数
            serialPort->setBaudRate(115200);                          //波特率115200
            serialPort->setDataBits(QSerialPort::Data8);              //数据位8
            serialPort->setStopBits(QSerialPort::OneStop);            //停止位1
            serialPort->setParity(QSerialPort::NoParity);             //校验位 无
            serialPort->setFlowControl(QSerialPort::NoFlowControl);   //设置为无流控制
            serialPort->setReadBufferSize(40960);                     //最大缓存40960
            QByteArray sendData("XX\n");//sendData的数据
            // 写入发送缓存区
            qint64 sendDataLen = serialPort->write(sendData);
            qDebug() << "checkDeviceConnectPort================sendDataLen=====" << sendDataLen;
            qApp->processEvents();
            qDebug() << "SerialPortManage::checkDeviceConnectPort=================processEvents================" << PRINTTIME;
            while(serialPort->isOpen() && serialPort->waitForReadyRead(3000)) {
                QString array = serialPort->readAll();
                qDebug() << "SerialPortManage::checkDeviceConnectPort=====================array============" << array << PRINTTIME;
                tempData.append(array);
                if(array.isEmpty()) {
                    qApp->processEvents();
                }

                if(tempData.contains("end"))
                {
                    qDebug() << "checkDeviceConnectPort=================tempData================" << tempData;
                    break;
                }

            }

            if(openName.size() > 0)
            {
                break;
            }

        }

    } //end foreach(

    qDebug() << "checkDeviceConnectPort=================openName=================" << openName << PRINTTIME;
    serialPort->close();
    serialPort->deleteLater();
    return openName;
}

void Dialog::slotBtn4()
{
    qDebug() << "Dialog::slotBtn4===1========================currentThreadId=====" << QThread::currentThreadId() << PRINTTIME;
    QFuture<QString> future = QtConcurrent::run(checkDeviceConnectPort);

    while (!future.isFinished()) {
        QApplication::processEvents(QEventLoop::AllEvents, 30);
    }

    qDebug() << "Dialog::slotBtn4============================result==============" << future.result() << PRINTTIME;
    qDebug() << "Dialog::slotBtn4===2========================currentThreadId=====" << QThread::currentThreadId() << PRINTTIME;

}

运行结果:

从上面可以看到,待线程函数执行完了,才会执行

qDebug() << "Dialog::slotBtn4============================result==============" << future.result() << PRINTTIME;
    qDebug() << "Dialog::slotBtn4===2========================currentThreadId=====" << QThread::currentThreadId() << PRINTTIME;

的代码,这样就可以根据结果处理后续的逻辑了,同时也不会卡界面。

完整代码中下:

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QThread>

QT_BEGIN_NAMESPACE
namespace Ui { class Dialog; }
QT_END_NAMESPACE

class WorkerThread;
class Worker;

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = nullptr);
    ~Dialog();

    void initData();


public slots:
    void slotBtn1();
    void slotBtn2();
    void slotBtn3();
    void slotBtn4();

    void handleResults1();
    void handleResults2();

signals:
    void operate(const QString &result);

private:
    Ui::Dialog *ui;
    WorkerThread *m_workerThread{nullptr};
    QThread workerThread;
    Worker *m_worker{nullptr};
};
#endif // DIALOG_H

dialog.cpp文件

#include "dialog.h"
#include "ui_dialog.h"
#include "workerthread.h"
#include "worker.h"
#include <QDebug>
#include <QSerialPort>
#include <QtConcurrent>
#include <QTime>
#include <QDebug>
#include <QEventLoop>
#include <QtConcurrentMap>
#include <QSerialPortInfo>

using namespace QtConcurrent;

#define PRINTTIME QDateTime::currentDateTime().toString("yyyy.MM.dd hh:mm:ss.zzz");

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::Dialog)
{
    ui->setupUi(this);
    initData();

}

Dialog::~Dialog()
{
    workerThread.quit();
    workerThread.wait();
    m_workerThread->quit();
    m_workerThread->wait();
    delete ui;
}

void Dialog::initData()
{
    m_workerThread = new WorkerThread(this);
    connect(m_workerThread, &WorkerThread::resultReady, this, &Dialog::handleResults1);
    //connect(m_workerThread, &WorkerThread::finished, m_workerThread, &Dialog::deleteLater);
    //m_workerThread->start();

    m_worker = new Worker;
    m_worker->moveToThread(&workerThread);
    connect(&workerThread, &QThread::finished, m_worker, &QObject::deleteLater);
    connect(this, &Dialog::operate, m_worker, &Worker::doWork);
    connect(m_worker, &Worker::resultReady, this, &Dialog::handleResults2);
    workerThread.start();

    connect(ui->btn1, SIGNAL(clicked()), this, SLOT(slotBtn1()));
    connect(ui->btn2, SIGNAL(clicked()), this, SLOT(slotBtn2()));
    connect(ui->btn3, SIGNAL(clicked()), this, SLOT(slotBtn3()));
    connect(ui->btn4, SIGNAL(clicked()), this, SLOT(slotBtn4()));
}


void Dialog::slotBtn1()
{
    qDebug() << "Dialog::slotBtn1================currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;
    m_workerThread->start();
    qDebug() << "Dialog::slotBtn1================currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;
    m_workerThread->getThreadFun();
}

void Dialog::slotBtn2()
{
    qDebug() << "Dialog::slotBtn2=======1========currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;
    emit operate("Worker");
    qDebug() << "Dialog::slotBtn2=======2========currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;
    m_worker->getThreadFun();
}


int threadFun3(int a1, int a2)
{
    qDebug() << "threadFun3======================currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;
    QThread::sleep(2);
    qDebug() << "threadFun3======================currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;
    return a1 + a2;
}

void Dialog::slotBtn3()
{
    int a1 = 5092;
    int a2 = 542451;
    QString str = "AAAAAAAAAAAA";
    qDebug() << "Dialog::slotBtn3=======1========currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;
    QFuture<int> future =QtConcurrent::run(threadFun3, a1, a2);
    int result = future.result();
    qDebug() << "Dialog::slotBtn3=======2========currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;
    qDebug() << "Dialog::slotBtn3================result================" << result << PRINTTIME;
}


//这里检测串口连接设备,连上设备才算打开串口成功
QString checkDeviceConnectPort()
{
    QString openName = "";
    QString tempData{""};
    QThread::sleep(2);
    qDebug() << "checkDeviceConnectPort======================currentThreadId=====" << QThread::currentThreadId() << PRINTTIME;
    QSerialPort *serialPort = new QSerialPort();
    foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
        serialPort->setPort(info);
        if(info.portName().contains("Bluetooth", Qt::CaseInsensitive))
            continue;


        bool isOpen = serialPort->open(QIODevice::ReadWrite);
        qDebug() << "checkDeviceConnectPort(================isOpen==" << isOpen << info.portName() << PRINTTIME;
        if(isOpen)
        {
            //设置参数
            serialPort->setBaudRate(115200);                          //波特率115200
            serialPort->setDataBits(QSerialPort::Data8);              //数据位8
            serialPort->setStopBits(QSerialPort::OneStop);            //停止位1
            serialPort->setParity(QSerialPort::NoParity);             //校验位 无
            serialPort->setFlowControl(QSerialPort::NoFlowControl);   //设置为无流控制
            serialPort->setReadBufferSize(40960);                     //最大缓存40960
            QByteArray sendData("XX\n");//sendData的数据
            // 写入发送缓存区
            qint64 sendDataLen = serialPort->write(sendData);
            qDebug() << "checkDeviceConnectPort================sendDataLen=====" << sendDataLen;
            qApp->processEvents();
            qDebug() << "SerialPortManage::checkDeviceConnectPort=================processEvents================" << PRINTTIME;
            while(serialPort->isOpen() && serialPort->waitForReadyRead(3000)) {
                QString array = serialPort->readAll();
                qDebug() << "SerialPortManage::checkDeviceConnectPort=====================array============" << array << PRINTTIME;
                tempData.append(array);
                if(array.isEmpty()) {
                    qApp->processEvents();
                }

                if(tempData.contains("end"))
                {
                    qDebug() << "checkDeviceConnectPort=================tempData================" << tempData;
                    break;
                }

            }

            if(openName.size() > 0)
            {
                break;
            }

        }

    } //end foreach(

    qDebug() << "checkDeviceConnectPort=================openName=================" << openName << PRINTTIME;
    serialPort->close();
    serialPort->deleteLater();
    return openName;
}

void Dialog::slotBtn4()
{
    qDebug() << "Dialog::slotBtn4===1========================currentThreadId=====" << QThread::currentThreadId() << PRINTTIME;
    QFuture<QString> future = QtConcurrent::run(checkDeviceConnectPort);

    while (!future.isFinished()) {
        QApplication::processEvents(QEventLoop::AllEvents, 30);
    }

    qDebug() << "Dialog::slotBtn4============================result==============" << future.result() << PRINTTIME;
    qDebug() << "Dialog::slotBtn4===2========================currentThreadId=====" << QThread::currentThreadId() << PRINTTIME;

}


void Dialog::handleResults1()
{
    qDebug() << "Dialog::handleResults1==========currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;
}

void Dialog::handleResults2()
{
    qDebug() << "Dialog::handleResults2==========currentThreadId=======" << QThread::currentThreadId() << PRINTTIME;
}
QT       += core gui serialport concurrent

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    dialog.cpp \
    worker.cpp \
    workerthread.cpp

HEADERS += \
    dialog.h \
    worker.h \
    workerthread.h

FORMS += \
    dialog.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

UI布局:

参考:

QFutureWatcher获取QtConcurrent::run线程函数的返回值_qt怎样异步获取qtconcurrent::run创建的线程的返回结果-CSDN博客

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

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

相关文章

matlab appdesigner系列-仪器仪表3-旋钮

旋钮&#xff0c;同过旋转显示特定的值 示例&#xff1a;模拟收音机调频 操作步骤&#xff1a; 1&#xff09;将旋钮、标签按钮拖拽到画布上&#xff0c;将标签文字修改为&#xff1a;欢迎收听&#xff0c;并将旋钮其数值范围改为90-107 2&#xff09;设置旋钮的回调函数 代…

实现屏蔽 Ctrl + Alt + Del 、Ctrl + Shift + Esc 等热键(一)

前面几篇我们都讲解了很多有关 winlogon 挂钩的事情。拦截系统热键的非驱动方式是比较复杂的。本节就复现《禁止CtrlAltDel、WinL等任意系统热键》一文中的方法四&#xff0c;实现拦截 Ctrl Alt Del 等热键。其实通过 heiheiabcd 给出的方法从 WMsgKMessageHandler 入手并不是…

数字图像处理(实践篇)三十二 OpenCV-Python比较两张图片的差异

目录 一 方案 二 实践 ​通过计算两张图像像素值的均方误差(MSE)来比较两张图像。差异大的两张图片具有较大的均方差值,相反,相似的图片间则具有较小的均方差值。需要注意的是。待比较的两张图像要具有相同的高度、宽度和通道数。 一 方案 ①导入依赖库 import cv2 import…

【项目管理】CMMI-管理性能与度量

管理性能与度量 (Managing Performance and Measurement, MPM)的目的在于开发和维持度量能力来管理开发过程性能&#xff0c;以实现公司业务目标&#xff0c;更直接来说&#xff0c;将管理和改进工作集中在成本、进度表和质量性能上&#xff0c;最大限度地提高业务投资回报。 1…

vscode copilot怎么去掉提示代码(ghost text or incline completion)

原因&#xff1a;最近在刷题&#xff0c;被这个提示烦死了&#xff0c;记录一下怎么关掉&#xff0c;防止将来需要开启找不到了XD. 1.直接ctrlshiftp召唤设置 2.输入preferences: open usr settings找到如图第一个 3.去掉这个方框的勾选 ps直接在extension里disable不行呢 不…

OpenHarmony—仅允许在表达式中使用typeof运算符

规则&#xff1a;arkts-no-type-query 级别&#xff1a;错误 ArkTS仅支持在表达式中使用typeof运算符&#xff0c;不允许使用typeof作为类型。 TypeScript let n1 42; let s1 foo; console.log(typeof n1); // number console.log(typeof s1); // string let n2: typeof …

Arduino Uno R3通过ESP-01S连接网络

一、材料准备 Arduino Uno R3开发板 1 USB串口通信数据线&#xff08;Uno开发板使用&#xff09; 1 ESP8266-01S Wi-Fi模块 1 ESP8266固件烧录下载器&#xff08;烧录固件使用&#xff09; 1 WiFi无线收发转接板&#xff08;适用于ESP-01S、ESP-01&#xff09; 杜邦线…

iOS 面试 Swift基础题

一、Swift 存储属性和计算属性比较&#xff1a; 存储型属性:用于存储一个常量或者变量 计算型属性: 计算性属性不直接存储值,而是用 get / set 来取值 和 赋值,可以操作其他属性的变化. 计算属性可以用于类、结构体和枚举&#xff0c;存储属性只能用于类和结构体。存储属性可…

跟着cherno手搓游戏引擎【13】着色器(shader)

创建着色器类&#xff1a; shader.h:初始化、绑定和解绑方法&#xff1a; #pragma once #include <string> namespace YOTO {class Shader {public:Shader(const std::string& vertexSrc, const std::string& fragmentSrc);~Shader();void Bind()const;void Un…

总线协议:基于RS-485的Modbus协议(1):物理层实现

0 工具准备 Modbus协议规范&#xff08;中文&#xff09; 1 基于RS-485的Modbus协议的物理层实现 Modbus协议的物理层实现可以通过RS-485、RS-232、RS-422来实现&#xff0c;不过通常都是用RS-485作为Modbus协议的物理层实现。有关RS-485、RS-232、RS-422的区别如下&#xff1…

MySQL的SQL MODE

目录 举例&#xff1a; --常见SQL mode --mysql8 sql_mode 官方文档 https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html --查看全局的SQL MODE select global.sql_mode; --查看当前会话的SQL MODE select session.sql_mode; --运行时修改全局的SQL mode set gl…

【数据分享】1929-2023年全球站点的逐年平均气温数据(Shp\Excel\免费获取)

气象数据是在各项研究中都经常使用的数据&#xff0c;气象指标包括气温、风速、降水、湿度等指标&#xff0c;其中又以气温指标最为常用&#xff01;说到气温数据&#xff0c;最详细的气温数据是具体到气象监测站点的气温数据&#xff01;本次我们为大家带来的就是具体到气象监…

ChatGPT与文心一言:智能回复与语言准确性的较量

在当今数字化时代&#xff0c;随着人们对智能化技术的需求不断增长&#xff0c;智能回复工具也成为了日常生活中不可或缺的一部分。ChatGPT和文心一言作为两个备受瞩目的智能回复工具&#xff0c;在智能回复、语言准确性以及知识库丰富度等方面各有卓越之处。 本文将对这两者进…

每日一题——LeetCode1351.统计有序矩阵中的负数

方法一 暴力枚举&#xff1a; var countNegatives function(grid) {let count0for(let arr of grid){for(let num of arr){if(num<0){count}}}return count }; 消耗时间和内存情况&#xff1a; 方法二 二分法&#xff1a; var countNegatives function(grid) {const m …

Node.js的学习1

Node.js简介 浏览器是JavaScript的前端运行环境Node.js是JavaScript的后端运行环境Node.js中无法调用DOM和BOM等浏览器内置API 终端中的快捷键 使用向上箭头&#xff0c;可以快速定位到上一次执行的命令使用tab键&#xff0c;可以快速补全路径使用esc键&#xff0c;可以快速清…

工程对接大模型流式和非流式对话底层原理解析

文章目录 前言一、非流式输出设计二、stream流式输出设计三、手撸一个流式输出项目总结 前言 之前对接过OpenAi大模型的官方API&#xff0c;可以看到它有一个Stream参数&#xff0c;设置成true的时候就是流式的对话输出&#xff0c;现象就是一段一段的往外崩。 官方手册的地址…

qemu调试kernel启动(从第一行汇编开始)

一、背景 大部分qemu调试kernel 都是讲解从start_kernel开始设置断点&#xff0c;然后开启调试&#xff1b; 但是我们熟悉linux启动流程的伙伴肯定知道&#xff0c;在start_kernel之前还有一段汇编&#xff0c;包括初始化页表及mmu等操作&#xff0c; 这部分如何调试呢&#x…

AOP+Redisson 延时队列,实现缓存延时双删策略

一、缓存延时双删 关于缓存和数据库中的数据保持一致有很多种方案&#xff0c;但不管是单独在修改数据库之前&#xff0c;还是之后去删除缓存都会有一定的风险导致数据不一致。而延迟双删是一种相对简单并且收益比较高的实现最终一致性的方式&#xff0c;即在删除缓存之后&…

HarmonyOS --@state状态装饰器

在声明式UI中&#xff0c;是以状态驱动视图更新。 状态&#xff08;state&#xff09;&#xff1a;指驱动视图更新的数据&#xff08;被装饰器标记的变量&#xff09;。 试图&#xff08;view&#xff09;&#xff1a;基于UI描述渲染得到用户界面 State装饰器标记的变量必须初…

【华为 ICT HCIA eNSP 习题汇总】——题目集11

1、某公司的内网用户采用 NAT 技术的 NO-pat 方式访问互联网&#xff0c;若所有的公网地址均被使用&#xff0c;则后续上网的内网用户会&#xff08;&#xff09;。 A、挤掉前一个用户&#xff0c;强制进行 NAT 转换上网 B、将报文同步到其他 NAT 转换设备上进行 NAT 转换 C、自…