qt-C++笔记之QThread使用

news2024/7/30 4:45:38

qt-C++笔记之QThread使用

——2024-05-26 下午

在这里插入图片描述

在这里插入图片描述

code review!

参考博文:
qt-C++笔记之使用QtConcurrent异步地执行槽函数中的内容,使其不阻塞主界面
qt-C++笔记之QThread使用

文章目录

  • qt-C++笔记之QThread使用
    • 一:Qt中几种多线程方法
      • 1.1. 使用 `QThread` 和 Lambda
      • 1.2. 使用 `QThread::create()`
      • 1.3. 继承 `QThread` 并重写 `run()`
      • 1.4. 使用 `QObject` 派生类与 `QThread`
      • 1.5. 使用 `QtConcurrent::run()`
      • 总结
    • 二.方法一:继承QThread并重写其run()方法
      • 2.1.代码一:运行全局纯函数
      • 2.2.代码二:运行全局纯函数
      • 2.3.代码一和代码二的区别
        • 2.3.1 带`input`参数的构造函数
        • 2.3.2. 带`input`和`parent`参数的构造函数
        • 2.3.3 总结
      • 2.4.代码三:直接在run()方法中写运行逻辑
      • 2.5.代码四:直接在run()方法中写运行逻辑,并在QCoreApplication::quit()前执行一些打印
      • 2.6.代码五:通过继承QThread的方式来运行一个纯函数,并将参数通过类的成员变量传递给这个函数
      • 2.7.代码六:通过继承QThread的方式来运行一个纯函数,并将参数通过类的成员变量传递给这个函数
    • 三.方法二:将任务放在QObject派生类中,并`moveToThread()`在QThread中运行这个QObject
      • 3.1. 代码一:运行成员函数例程,让 Worker 类继承自 QObject,然后使用一个 QThread 实例来在另一个线程中运行这个 Worker 对象
      • 3.2. 代码二:运行成员函数例程,让 Worker 类继承自 QObject,然后使用一个 QThread 实例来在另一个线程中运行这个 Worker 对象
    • 四.方法三:直接使用 QThread 和 Lambda
    • 五.方法四:`QThread::create(Qt 5.10 及以上)`
      • 5.1.提要
        • 5.1.1.QThread::create()代码一
        • 5.1.2.QThread::create()代码二
    • 六.方法五:`QtConcurrent::run()`

一:Qt中几种多线程方法

五种不同的多线程实现方法在Qt中的特点和适用场景:

方法描述优点缺点适用场景
直接使用 QThread 和 Lambda使用 QThread 对象和信号槽连接一个lambda表达式来执行代码。简单快速;灵活定义启动行为。精细控制线程较少;线程复用不便。快速实现简单的后台任务,不需要复用线程。
使用 QThread::create()使用 QThread::create() 创建并自动启动线程来执行函数或lambda。极简代码;自动线程管理。对线程的控制较为有限;不易于复用。适合快速启动一次性后台任务,不需要线程间交互。
继承 QThread 并重写 run()通过继承 QThread 并重写其 run() 方法来定义线程行为。完全控制线程行为;能够处理复杂逻辑。实现复杂;易误用(如直接操作GUI)。需要精细控制线程行为或有复杂线程逻辑的场景。
使用 QObject 派生类与 QThread创建 QObject 派生类,并在移至 QThread 的对象上执行任务。分离工作和线程管理;完全的信号和槽支持。设置相对繁琐;代码量较多。需要线程频繁与主线程通信或任务较为复杂的场景。
使用 QtConcurrent::run()使用Qt并发模块的 QtConcurrent::run() 在线程池中运行函数或成员函数。简单易用;自动管理线程池;减少资源消耗。对线程控制较少;不适合特定线程管理需求。适用于执行独立的并发任务,不需要细粒度线程控制。

1.1. 使用 QThread 和 Lambda

这种方法直接使用 QThread 的实例,并通过信号和槽系统将lambda表达式绑定至 QThread::started 信号。这种方法允许灵活地定义线程开始时执行的代码,而不需创建额外的类或使用 QtConcurrent。它适合快速简单的线程使用,尤其是当你不需要频繁与主线程通信或管理复杂的线程生命周期时。

1.2. 使用 QThread::create()

QThread::create() 是Qt 5.10引入的一个便捷函数,它基本上是创建线程与绑定任务的简化版。你只需要提供一个函数或lambda表达式,QThread::create() 会自动创建线程并在启动线程时执行这个函数。

auto thread = QThread::create([](){
    // 执行一些任务
});
thread->start();

这种方法的优点是极其简单,但它通常不适用于需要复杂线程管理或多次复用线程的场景。

1.3. 继承 QThread 并重写 run()

这是一种更传统的方法,通过继承 QThread 并重写其 run() 方法实现。这种方法提供了最大的灵活性,允许你控制线程的准确行为,但也需要更多的代码和复杂的错误处理。

class WorkerThread : public QThread
{
protected:
    void run() override {
        // 执行任务
    }
};

1.4. 使用 QObject 派生类与 QThread

这是Qt推荐的多线程使用方式。你创建一个 QObject 派生类来封装工作任务,然后将这个对象的实例移动到 QThread 中。

class Worker : public QObject
{
    Q_OBJECT
public slots:
    void doWork() {
        // 执行任务
    }
};

QThread *thread = new QThread();
Worker *worker = new Worker();
worker->moveToThread(thread);
connect(thread, &QThread::started, worker, &Worker::doWork);
thread->start();

这种方法适合需要线程与主线程频繁交互的场景,因为它完全兼容Qt的信号与槽机制。

1.5. 使用 QtConcurrent::run()

QtConcurrent::run() 是处理并发运算的另一种高级方法,它可以非常方便地在后台线程池中运行函数或成员函数。

QtConcurrent::run([](){
    // 执行某些操作
});

这种方法非常适合不需要细粒度控制线程行为的场景,且可以自动管理线程池,避免创建和销毁线程的开销。

总结

  • 直接使用 QThread 和 Lambda:适合快速、一次性的简单后台任务。
  • 使用 QThread::create():简化版的线程创建和任务绑定,适合不需要复用线程的场景。
  • 继承 QThread:适用于需要完全控制线程行为的复杂场景。
  • 使用 QObject 派生类与 QThread:Qt推荐的方式,适合需要线程间频繁通信的场景。
  • 使用 QtConcurrent::run():适用于简单并发任务,自动线程池管理,减少资源消耗。

二.方法一:继承QThread并重写其run()方法

2.1.代码一:运行全局纯函数

#include <QCoreApplication>
#include <QThread>
#include <QDebug>

// 纯函数的定义,这个函数只进行计算并返回结果,不涉及任何的状态修改
int pureFunction(int x) {
    return x * x;
}

// 创建一个线程类,用于运行纯函数
class WorkerThread : public QThread {
public:
    WorkerThread(int input) : inputValue(input) {}

protected:
    void run() override {
        int result = pureFunction(inputValue);
        qDebug() << "计算结果:" << result;
    }

private:
    int inputValue;
};

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    // 初始化一个线程对象,传入参数5
    WorkerThread thread(5);

    // 连接线程的finished信号到QCoreApplication的quit槽,确保应用程序在线程结束后退出
    QObject::connect(&thread, &QThread::finished, &a, &QCoreApplication::quit);

    // 启动线程
    thread.start();

    // 进入事件循环
    return a.exec();
}

运行

计算结果: 25

2.2.代码二:运行全局纯函数

#include <QCoreApplication>
#include <QThread>
#include <QDebug>

// 全局纯函数
void globalPureFunction(int param) {
    qDebug() << "运行在线程:" << QThread::currentThreadId();
    qDebug() << "接收到的参数:" << param;
    // 模拟一些处理过程
    QThread::sleep(2); // 假装我们在做一些耗时的工作
    qDebug() << "处理完成";
}

// 线程类
class WorkerThread : public QThread {
    int m_param;
public:
    WorkerThread(int param, QObject *parent = nullptr) : QThread(parent), m_param(param) {}

protected:
    void run() override {
        globalPureFunction(m_param); // 在新线程中调用全局纯函数
    }
};

// 主函数
int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    int inputValue = 42; // 示例参数值
    WorkerThread *thread = new WorkerThread(inputValue);
    thread->start(); // 启动线程

    QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater);
    QObject::connect(thread, &QThread::finished, &a, &QCoreApplication::quit);

    return a.exec();
}

运行

运行在线程: 0x7fd2ea57f700
接收到的参数: 42
处理完成

2.3.代码一和代码二的区别

在Qt中,处理QThread和其他继承自QObject的类时,构造函数中的parent参数非常关键,它影响对象的内存管理和事件传递机制。让我们比较一下这两种构造函数的定义和它们的实际用途:

2.3.1 带input参数的构造函数
WorkerThread(int input) : inputValue(input) {}

这个构造函数只接受一个input参数,并初始化成员变量inputValue。这里没有显式地处理parent参数:

  • 作用:初始化inputValue
  • 内存管理:这个WorkerThread对象的生命周期需要显式管理(比如通过在堆上创建和删除,或者确保其作用域在使用中不会结束),因为没有父对象来自动管理它。
  • 适用场景:当你不需要将线程对象的生命周期与其他Qt对象关联时,或者当你想要通过代码显式管理线程的生命周期时使用。
2.3.2. 带inputparent参数的构造函数
WorkerThread(int input, QObject *parent = nullptr) : QThread(parent), inputValue(input) {}

这个构造函数接受一个input参数和一个可选的parent参数,默认为nullptr。它在初始化列表中调用了QThread的构造函数,传递了parent参数:

  • 作用:初始化inputValue并设置父对象。
  • 内存管理:如果指定了父对象(parent不为nullptr),这个WorkerThread对象的生命周期将由其父对象自动管理(父对象销毁时,它也会被销毁)。如果parentnullptr,则其生命周期需要手动管理。
  • 适用场景:当你希望线程的生命周期与某个Qt对象(如窗口或其他组件)绑定时使用。这样可以简化内存管理,使线程的生命周期与其父对象相匹配。
2.3.3 总结

添加parent参数的版本提供了更灵活的内存管理选项,允许线程对象以树形层次结构中的一部分被管理,这对于复杂的Qt应用程序来说非常有用。没有parent参数的版本则简单、直接,更适合生命周期管理相对明确或简单的场合。在实际应用中,选择哪种方式取决于你的具体需求和线程管理策略。

2.4.代码三:直接在run()方法中写运行逻辑

#include <QCoreApplication>
#include <QThread>
#include <iostream>

// WorkerThread 类,继承自 QThread
class WorkerThread : public QThread
{
public:
    WorkerThread(QObject *parent = nullptr) : QThread(parent) {}

    // 重载 run 方法
    void run() override {
        // 纯函数任务内容
        for (int i = 0; i < 10; ++i) {
            std::cout << "工作线程运行中: " << i << std::endl;
            QThread::sleep(1); // 模拟耗时操作,每次循环暂停1秒
        }
        std::cout << "工作线程结束运行。" << std::endl;
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 创建 WorkerThread 对象
    WorkerThread thread;

    // 连接线程完成信号到退出槽,确保线程完成后应用程序退出
    QObject::connect(&thread, &WorkerThread::finished, &a, &QCoreApplication::quit);

    // 启动线程
    thread.start();

    // 进入 Qt 事件循环
    return a.exec();
}

运行

工作线程运行中: 0
工作线程运行中: 1
工作线程运行中: 2
工作线程运行中: 3
工作线程运行中: 4
工作线程运行中: 5
工作线程运行中: 6
工作线程运行中: 7
工作线程运行中: 8
工作线程运行中: 9
工作线程结束运行。

2.5.代码四:直接在run()方法中写运行逻辑,并在QCoreApplication::quit()前执行一些打印

#include <QCoreApplication>
#include <QThread>
#include <QDebug>

// 纯函数,作为线程任务
void runTask() {
    for (int i = 0; i < 10; ++i) {
        QThread::sleep(1); // 模拟耗时任务
        qDebug() << "工作在线程 " << QThread::currentThreadId() << " 中执行: " << i;
    }
}

// 自定义的线程类
class TaskThread : public QThread {
    Q_OBJECT // 添加 Q_OBJECT 宏以支持信号和槽
public:
    TaskThread(QObject *parent = nullptr) : QThread(parent) {}

protected:
    void run() override {
        runTask(); // 在新线程中运行纯函数
        emit taskCompleted(); // 发射任务完成信号
    }

signals:
    void taskCompleted();
};

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    TaskThread thread;
    QObject::connect(&thread, &TaskThread::taskCompleted, &a, [&]() {
        qDebug() << "任务完成,信号在主线程 " << QThread::currentThreadId() << " 中被处理";
        QCoreApplication::quit(); // 完成后退出程序
    });

    qDebug() << "主线程ID: " << QThread::currentThreadId();
    thread.start(); // 启动线程

    return a.exec();
}

#include "main.moc" // 如果你不是使用 qmake,确保 moc 处理这个文件

运行

主线程ID:  0x7f7e73b0d780
工作在线程  0x7f7e6ef9d700  中执行:  0
工作在线程  0x7f7e6ef9d700  中执行:  1
工作在线程  0x7f7e6ef9d700  中执行:  2
工作在线程  0x7f7e6ef9d700  中执行:  3
工作在线程  0x7f7e6ef9d700  中执行:  4
工作在线程  0x7f7e6ef9d700  中执行:  5
工作在线程  0x7f7e6ef9d700  中执行:  6
工作在线程  0x7f7e6ef9d700  中执行:  7
工作在线程  0x7f7e6ef9d700  中执行:  8
工作在线程  0x7f7e6ef9d700  中执行:  9
任务完成,信号在主线程  0x7f7e73b0d780  中被处理

2.6.代码五:通过继承QThread的方式来运行一个纯函数,并将参数通过类的成员变量传递给这个函数

#include <QCoreApplication>
#include <QThread>
#include <QDebug>

// 纯函数,有传参
int square(int x) {
    return x * x;
}

// 继承QThread的类,重写run()函数
class MyThread : public QThread {
protected:
    void run() override {
        // 调用纯函数,并传参
        int result = square(x);
        qDebug() << "Result:" << result;
    }

public:
    int x;
};

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    // 创建MyThread对象
    MyThread thread;

    // 在main函数中声明参数,并传入MyThread对象
    int param = 10;
    thread.x = param;

    // 启动MyThread对象
    thread.start();

    // 等待MyThread对象结束
    thread.wait();

    return a.exec();
}

运行

Result: 100

2.7.代码六:通过继承QThread的方式来运行一个纯函数,并将参数通过类的成员变量传递给这个函数

#include <QCoreApplication>
#include <QThread>
#include <QDebug>

// 纯函数的声明
void pureFunction(int a, int b);

// 继承自 QThread 的类
class WorkerThread : public QThread {

public:
    // 构造函数
    WorkerThread(int a, int b, QObject *parent = nullptr) : QThread(parent), m_a(a), m_b(b) {}

protected:
    // 重写 run 方法
    void run() override {
        // 在新线程中调用纯函数
        qDebug() << "线程开始执行";
        pureFunction(m_a, m_b);
        qDebug() << "线程执行完成";
    }

private:
    int m_a, m_b;  // 成员变量,用于存储传递给纯函数的参数
};

// 纯函数的实现
void pureFunction(int a, int b) {
    // 执行一些计算或处理
    int result = a + b;
    qDebug() << "纯函数执行结果:" << result;
}

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    // 创建 WorkerThread 对象,传递参数给纯函数
    WorkerThread thread(10, 20);
    // 启动线程
    thread.start();
    // 等待线程执行完成
    thread.wait();

    return a.exec();
}

运行

线程开始执行
纯函数执行结果: 30
线程执行完成

三.方法二:将任务放在QObject派生类中,并moveToThread()在QThread中运行这个QObject

3.1. 代码一:运行成员函数例程,让 Worker 类继承自 QObject,然后使用一个 QThread 实例来在另一个线程中运行这个 Worker 对象

// 包含必要的头文件
#include <QCoreApplication>
#include <QThread>
#include <QDebug>

// Worker 类定义
class Worker : public QObject {
    Q_OBJECT

public:
    Worker() {}
    virtual ~Worker() {}

public slots:
    void process() {
        // 输出当前线程信息
        qDebug() << "Worker thread running in thread:" << QThread::currentThreadId();
        // 模拟耗时操作
        QThread::sleep(3);
        qDebug() << "Worker process completed.";
        emit finished();
    }

signals:
    void finished();
};

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    // 创建线程对象
    QThread workerThread;
    Worker worker;

    // 将 worker 对象移动到新建的线程
    worker.moveToThread(&workerThread);

    // 连接信号和槽
    QObject::connect(&workerThread, &QThread::started, &worker, &Worker::process);
    QObject::connect(&worker, &Worker::finished, &workerThread, &QThread::quit);
    QObject::connect(&worker, &Worker::finished, &worker, &Worker::deleteLater);
    QObject::connect(&workerThread, &QThread::finished, &workerThread, &QThread::deleteLater);

    // 启动线程
    workerThread.start();

    // 运行事件循环
    int result = a.exec();

    // 等待线程结束
    workerThread.wait();

    return result;
}

#include "main.moc"

运行

Worker thread running in thread: 0x7f1943a36700
Worker process completed.
double free or corruption (out)
15:43:36: The program has unexpectedly finished.

3.2. 代码二:运行成员函数例程,让 Worker 类继承自 QObject,然后使用一个 QThread 实例来在另一个线程中运行这个 Worker 对象

#include <QCoreApplication>
#include <QThread>
#include <QDebug>

// Worker类,负责执行实际的计算
class Worker : public QObject {
    Q_OBJECT

public:
    Worker(int a, int b) : m_a(a), m_b(b) {}

public slots:
    void process() {
        int result = m_a + m_b;  // 简单的加法计算
        qDebug() << "计算结果:" << result;
        emit finished();
    }

signals:
    void finished();

private:
    int m_a;
    int m_b;
};

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    int value1 = 5, value2 = 3;
    Worker *worker = new Worker(value1, value2);
    QThread *thread = new QThread;

    // 将worker移动到线程
    worker->moveToThread(thread);

    // 连接信号和槽
    QObject::connect(thread, &QThread::started, worker, &Worker::process);
    QObject::connect(worker, &Worker::finished, thread, &QThread::quit);
    QObject::connect(worker, &Worker::finished, worker, &QObject::deleteLater);
    QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater);
    QObject::connect(thread, &QThread::finished, &a, &QCoreApplication::quit); // 确保应用退出

    // 启动线程
    thread->start();

    return a.exec();
}

#include "main.moc"

运行

计算结果: 8

四.方法三:直接使用 QThread 和 Lambda

#include <QCoreApplication>
#include <QThread>
#include <QDebug>

// 纯函数定义,用于计算两个整数的和
int add(int a, int b) {
    return a + b;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 创建线程对象
    QThread* thread = new QThread;
    int x = 3, y = 4;

    // 将任务移至线程,使用lambda表达式
    QObject::connect(thread, &QThread::started, [=]() mutable {
        int result = add(x, y);
        qDebug() << "The sum of" << x << "and" << y << "is" << result;
        thread->quit();  // 线程任务完成,请求退出线程
    });

    // 清理线程资源
    QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater);

    // 启动线程
    thread->start();

    return a.exec();
}

运行

The sum of 3 and 4 is 7

五.方法四:QThread::create(Qt 5.10 及以上)

5.1.提要

  • 直接在 QThread类中没有提供直接创建并启动线程执行特定函数的方法(例如 QThread::create 是 C++11 后Qt 5.10 添加的功能,如果您使用的Qt版本较旧,这一功能可能不可用)

  • 在Qt中使用QThread来运行一个全局纯函数是一个比较通用的任务,在Qt中,通常通过继承QThread并重写run()方法来实现这一点,但使用QThread的能力来直接启动一个线程执行我们的函数。

5.1.1.QThread::create()代码一
#include <QCoreApplication>
#include <QThread>
#include <QDebug>

void performCalculation(int a, int b) {
    int result = a + b;
    qDebug() << "计算结果:" << result;
}

int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);

    QThread *thread = QThread::create(performCalculation, 5, 3);
    QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater);
    thread->start();

    return app.exec();
}
5.1.2.QThread::create()代码二
#include <QCoreApplication>
#include <QThread>
#include <QDebug>

// 全局纯函数
void performCalculation(int a, int b) {
    int result = a + b;  // 简单的加法计算
    qDebug() << "计算结果:" << result;
}

// 线程执行的函数
void runInThread(int a, int b) {
    // 创建线程对象
    QThread* thread = QThread::create([=](){
        performCalculation(a, b);
    });

    // 连接线程结束信号到删除槽,确保资源被清理
    QObject::connect(thread, &QThread::finished, thread, &QObject::deleteLater);

    // 启动线程
    thread->start();
}

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    // 在线程中执行全局函数
    runInThread(5, 3);

    return a.exec();
}

六.方法五:QtConcurrent::run()

#include <QCoreApplication>
#include <QThread>
#include <QDebug>
#include <QtConcurrent>

// 全局纯函数
void performCalculation(int a, int b) {
    int result = a + b;  // 简单的加法计算
    qDebug() << "在线程" << QThread::currentThreadId() << "计算结果:" << result;
}

int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);

    // 使用QtConcurrent运行全局函数
    int value1 = 5, value2 = 3;
    QFuture<void> future = QtConcurrent::run(performCalculation, value1, value2);

    // 等待任务完成
    future.waitForFinished();

    return app.exec();
}

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

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

相关文章

【二叉树】LeetCode.144:二叉树的前序遍历(小细节把握)

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;初阶初阶结构刷题 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 目录 1.题目描述&#xff1a;​编辑 2.问题分析&#xff1a; &#x1f354;函数解读&#xff1a; …

功率电感的设计步骤

文章目录 1&#xff1a;高导磁气隙&#xff08;铁氧体&#xff09;1.1设计原理1.2 设计步骤 2 铁粉芯2.1&#xff1a;设计原理2.2&#xff1a;设计步骤 TI电感设计 学习视频原链接 截图 1 截图1 截图1 截图 2 截图2 截图2 1&#xff1a;高导磁气隙&#xff08;铁氧体&#…

solidworks画螺栓学习笔记

螺栓 单位mm 六边形 直径16mm 水平约束 拉伸 选择厚度6mm 拉伸切除 画相切圆 切除厚度6mm&#xff0c;反向切除 &#xff0c;拔模角度45 螺栓 直径9mm&#xff0c;长度30mm 倒角 直径1mm&#xff0c;角度45 异形孔向导 螺纹线 偏移打勾&#xff0c;距离为2mm&#…

【C语言】八进制、十六进制

前言 在我们日常生活中使用的数往往是十进制的&#xff0c;而当我们学习C语言后我们会接触到许多不同的进制并且时常需要去思考与使用这些不同的进制&#xff08;尤其是2的幂相关的进制&#xff0c;因为这种计数系统比十进制更接近于计算机的二进制系统&#xff09;&#xff0…

牛客网刷题 | BC100 直角三角形图案

目前主要分为三个专栏&#xff0c;后续还会添加&#xff1a; 专栏如下&#xff1a; C语言刷题解析 C语言系列文章 我的成长经历 感谢阅读&#xff01; 初来乍到&#xff0c;如有错误请指出&#xff0c;感谢&#xff01; 描述 KiKi学习了循环&am…

爽!AI手绘变插画,接单赚爆了!

我最近发现一款名叫Hyper-SD15-Scribble的AI项目&#xff0c;可以实现一键手绘变插画的功能&#xff0c;而且它搭载了字节出品的超快速生成图片的AI大模型Hyper-SD15&#xff0c;可以实现几乎实时生成图片&#xff0c;有了它&#xff0c;拿去接一些手绘商单分分钟出图&#xff…

java生产制造执行系统MES源码:系统环境:Java EE 8、Servlet 3.0、Apache Maven 3 2;

MES系统技术选型 系统环境&#xff1a;Java EE 8、Servlet 3.0、Apache Maven 3 2&#xff1b; 主框架&#xff1a;Spring Boot 2.2.x、Spring Framework 5.2.x、Spring Security 5.2.x 3 持久层&#xff1a;Apache MyBatis 3.5.x、Hibernate Validation 6.0.x、Alibaba Dru…

基于STM32实现智能气体检测报警系统

⬇帮大家整理了单片机的资料 包括stm32的项目合集【源码开发文档】 点击下方蓝字即可领取&#xff0c;感谢支持&#xff01;⬇ 点击领取更多嵌入式详细资料 问题讨论&#xff0c;stm32的资料领取可以私信&#xff01; 目录 引言环境准备智能气体检测报警系统基础代码示例&…

ZDH-智能营销-插件服务

目录 主题 项目源码 预览地址 安装包下载地址 插件服务 插件服务使用场景 插件服务日志 感谢支持 主题 本篇文章主要介绍ZDH-智能营销平台下的插件服务,包含插件的应用场景 项目源码 zdh_web: GitHub - zhaoyachao/zdh_web: 大数据采集,抽取平台 zdh_magic_mirror: …

AIGC002-LoRA让大模型微调更加轻盈方便!

AIGC002-LoRA让大模型微调更加轻盈方便&#xff01; 文章目录 0 论文工作1 论文方法2 效果 0 论文工作 这篇论文名为 LORA: LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS&#xff0c;作者是 Edward Hu 等人。它提出了一种名为 低秩自适应 (Low-Rank Adaptation, LoRA) 的新方…

AI 谈“浔川AI翻译机”

在天工AI&#xff0c;天工AI在全网搜索“浔川AI翻译机”。 1 创作助手谈“浔川AI翻译机”&#xff1a; “浔川AI翻译机”是一个利用人工智能技术进行语言翻译的设备或应用程序。它可以将一种语言的文字或口语翻译成另一种语言&#xff0c;以实现不同语言之间的沟通和理解。浔…

网络布线与数制转换

信号与传输介质 信号概述 什么是信号 信息 人对现实世界事物存在方式或运动状态的某种认识 数据 用于描述事物的某些属性的具体量值 信号 信息传递的媒介 例如&#xff0c;描述某一件物体&#xff0c;它的长、宽、高、质地、颜色、气味等就是用以形容该物体的数据。通…

图书管理系统——Java版

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a;JavaSE 顺序表的学习&#xff0c;点我 目录 图书管理系统菜单 基本框架&#xff1a; 书&#xff1a; 书架&#xff1a; 用户&#xff…

web及网络基础图文详解

目录 1.1TCP/IP 协议族 1.2TCP/IP 的分层管理 1.3TCP/IP通信传输流 1.4 与 HTTP 关系密切的协议 : IP、TCP 和 DNS &#xff08;1&#xff09;负责传输的 IP协议&#xff08;网络层&#xff09; &#xff08;2&#xff09;确保可靠的 TCP协议&#xff08;传输层&#xff…

sklearn实现线性回归

sklearn实现线性回归 一、数据集介绍二、使用sklearn实现线性回归一、数据集介绍 本案例使用女性身高体重数据集,数据集如下图所示: 可以看到,数据集有15行2列。 二、使用sklearn实现线性回归 sklearn中的线性模型模块是linear_model。这里使用linear_model下的普通线性…

TiDB学习4:Placement Driver

目录 1. PD架构 2. 路由功能 2. TSO 2.1 TSO 概念 2.2 TSO分配过程 2.3 TSO时间窗口 3. 调度 3.1 信息收集 3.2 生成调度(operator) 3.3 执行调度 4. Label 与高可用 4.1 Label 的配置 5. 小结 1. PD架构 PD是整个TiDB的总控&#xff0c;相当于集群的大脑 PD集成了…

易备数据备份软件: 快速备份 MySQL\SQL Server\Oracle\泛微 OA 数据库

易备数据备份软件支持对 SQL Server、Oracle、MySQL、PostgreSQL、MariaDB、泛微 OA 等数据库进行快速备份&#xff0c;备份过程不会对任何服务造成中断。 使用一份授权&#xff0c;可以备份无限量的数据库&#xff0c;不管数据库服务器是否在本机、本地网络、或是远程网络。可…

用LabVIEW进行CAN通信开发流程

本文详细介绍了在LabVIEW中开发CAN&#xff08;Controller Area Network&#xff09;通信的流程&#xff0c;包括硬件配置、软件编程和调试步骤。重点讨论了开发过程中需要注意的问题&#xff0c;如节点配置、数据帧格式和错误处理等&#xff0c;为开发高效可靠的CAN通信应用提…

可以在搜索结果中屏蔽指定网站的插件

可以在搜索结果中屏蔽指定网站的插件 | LogDict背景 在搜索引擎中搜索问题, 往往充斥各种无效内容 比如搜个技术类的问题, 前几页CSDN, 百度百家号, 百度经验, 百度知道, 腾讯云各类云爬的水文 CSDN基本都是复制粘贴的, 甚至格式都乱码了, 虽然我以前也干过 要复制粘贴无所谓, …