QT线程模块使用QThtead

文章展示了在Qt环境中使用QThread、QObject以及QtConcurrent实现多线程的方法。通过重写QThread的run方法或让类继承QObject并使用QRunnable,实现了数据生成、冒泡排序和快速排序的异步处理。同时,提到了线程池的使用,通过QThreadPool管理任务,根据系统资源动态调整线程数量。
摘要由CSDN通过智能技术生成

第一种方式:重写Qthread里的run方法

main.cpp

#include "mainwindow.h"

#include <QApplication>

int main(int argc, char* argv[])
{
    QApplication a(argc, argv);
    qRegisterMetaType<QVector<int>>("QVector<int>"); //注册 使用
    MainWindow w;

    w.show();
    return a.exec();
}

mainwindow.cpp

#include "mainwindow.h"
#include "mythread.h"
#include "ui_mainwindow.h"
#include <QLabel>
#include <QPushButton>
#include <QThread>

MainWindow::MainWindow(QWidget* parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //创建子线程

    Generate* gen = new Generate(this);
    Quicksort* quick = new Quicksort(this);
    Bubblesort* bubble = new Bubblesort(this);

    connect(this, &MainWindow::starting, gen, &Generate::recvNum);

    connect(ui->startBtn, &QPushButton::clicked, this, [=]() {
        emit this->starting(100000);        //启动线程
        gen->start(); });
    //接受数据
    connect(gen, &Generate::sayNum, quick, &Quicksort::recvArry);
    connect(gen, &Generate::sayNum, bubble, &Bubblesort::recvArry);
    //接受数据
    connect(gen, &Generate::sayNum, this, [=](QVector<int> v) {
        //接收到数据证明程序已经启动了 ,
        quick->start();
        bubble->start();
        //显示
        for (int i = 0; i < v.size(); ++i) {
            ui->randomList->addItem(QString::number(v.at(i)));
        }
        
    });
    //冒泡
    connect(bubble, &Bubblesort::finish, this, [=](QVector<int> v) {
        //        qDebug()<<"冒泡显示";
        //接收到数据证明程序已经启动了
        for (int i = 0; i < v.size(); ++i) {
            ui->bubbleList->addItem(QString::number(v.at(i)));
        }
    });

    //    //快排序
    connect(quick, &Quicksort::finish, this, [=](QVector<int> v) {
        //接收到数据证明程序已经启动了 ,
        //        qDebug() << "内置排序";
        for (int i = 0; i < v.size(); ++i) {
            ui->quickList->addItem(QString::number(v.at(i)));
        }
    });
}

void MainWindow::subThread()
{
    int num = 0;
    while (1) {
        num++;
        if (num == 100000) {
            break;
        }
        label->setText(QString::number(num));
        QThread::sleep(1);
    }
}

MainWindow::~MainWindow()
{
    delete ui;
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QLabel>
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow {
    Q_OBJECT

public:
    MainWindow(QWidget* parent = nullptr);
    ~MainWindow();
    void subThread();
    QLabel* label;

private:
    Ui::MainWindow* ui;
signals:
    void starting(int num);
};
#endif // MAINWINDOW_H

mythread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
#include <QWidget>
class Generate : public QThread {
    Q_OBJECT
public:
    explicit Generate(QWidget* parent = nullptr);
    void recvNum(int num);

signals:
    void sayNum(QVector<int>);

protected:
    void run() override;

private:
    int num;
};
//冒泡排序
class Bubblesort : public QThread {
    Q_OBJECT
public:
    explicit Bubblesort(QWidget* parent = nullptr);
    void recvArry(QVector<int>);

signals:
    void finish(QVector<int>);

protected:
    void run() override;

private:
    QVector<int> v;
};
//快速排序

class Quicksort : public QThread {
    Q_OBJECT
public:
    explicit Quicksort(QWidget* parent = nullptr);
    void recvArry(QVector<int>);

signals:
    void finish(QVector<int>);

protected:
    void run() override;

private:
    QVector<int> v;
};

#endif // MYTHREAD_H

mythread.cpp

#include "mythread.h"
#include <QElapsedTimer>
#include <QRandomGenerator>
#include <QVector>

Generate::Generate(QWidget* parent)
    : QThread { parent }
{
}
void Generate::run()
{
    qDebug() << "线程运行了,线程地址是" << Generate::currentThread();

    QVector<int> v;
    QElapsedTimer time;
    time.start();
    for (int i = 0; i < this->num; i++) {
        //        v.push_back(rand() % 10000);
        v.push_back(QRandomGenerator::global()->bounded(0, 1000));
    }
    int milsec = time.elapsed();
    qDebug() << "生成" << num << "个随机数"
             << "耗时" << milsec << "毫秒";
    emit this->sayNum(v);
}

void Generate::recvNum(int num)
{
    this->num = num;
}

//冒泡代码

Bubblesort::Bubblesort(QWidget* parent)
    : QThread(parent)
{
}

void Bubblesort::recvArry(QVector<int> v)
{
    this->v = v;
}

void Bubblesort::run()
{

    QElapsedTimer timer;
    timer.start();
    //冒泡排序
    qDebug() << "冒泡" << QThread::currentThread();
    for (int i = 0; i < v.size(); ++i) {
        for (int j = 0; j < v.size() - i - 1; ++j) {
            if (v[j] > v[j + 1]) {
                int temp = v[j];
                v[j] = v[j + 1];
                v[j + 1] = temp;
            }
        }
    }
    int milsec = timer.elapsed();
    qDebug() << "冒泡耗时" << milsec << "毫秒";
    emit finish(v);
};

//快速排序
Quicksort::Quicksort(QWidget* parent)
    : QThread(parent)
{
}

void Quicksort::recvArry(QVector<int> v)
{
    this->v = v;
}

void Quicksort::run()
{
    QElapsedTimer timer;
    timer.start();
    //快排序
    qDebug() << "快速排序" << QThread::currentThread();
    std::sort(v.begin(), v.end());

    int milsec = timer.elapsed();
    qDebug() << "快排耗时" << milsec << "毫秒";
    emit finish(v);
};

thread.pro

QT       += core gui

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 \
    mainwindow.cpp \
    mythread.cpp

HEADERS += \
    mainwindow.h \
    mythread.h

FORMS += \
    mainwindow.ui

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

mainwindow.ui / ui_mainwindow.h

/********************************************************************************
** Form generated from reading UI file 'mainwindow.ui'
**
** Created by: Qt User Interface Compiler version 6.3.1
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/

#ifndef UI_MAINWINDOW_H
#define UI_MAINWINDOW_H

#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QGroupBox>
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QListWidget>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QStatusBar>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QWidget>

QT_BEGIN_NAMESPACE

class Ui_MainWindow
{
public:
    QWidget *centralwidget;
    QVBoxLayout *verticalLayout_2;
    QWidget *widget;
    QHBoxLayout *horizontalLayout_3;
    QGroupBox *groupBox;
    QVBoxLayout *verticalLayout;
    QListWidget *randomList;
    QGroupBox *groupBox_2;
    QHBoxLayout *horizontalLayout;
    QListWidget *bubbleList;
    QGroupBox *groupBox_3;
    QHBoxLayout *horizontalLayout_2;
    QListWidget *quickList;
    QPushButton *startBtn;
    QMenuBar *menubar;
    QStatusBar *statusbar;

    void setupUi(QMainWindow *MainWindow)
    {
        if (MainWindow->objectName().isEmpty())
            MainWindow->setObjectName(QString::fromUtf8("MainWindow"));
        MainWindow->resize(800, 600);
        centralwidget = new QWidget(MainWindow);
        centralwidget->setObjectName(QString::fromUtf8("centralwidget"));
        verticalLayout_2 = new QVBoxLayout(centralwidget);
        verticalLayout_2->setObjectName(QString::fromUtf8("verticalLayout_2"));
        widget = new QWidget(centralwidget);
        widget->setObjectName(QString::fromUtf8("widget"));
        horizontalLayout_3 = new QHBoxLayout(widget);
        horizontalLayout_3->setObjectName(QString::fromUtf8("horizontalLayout_3"));
        groupBox = new QGroupBox(widget);
        groupBox->setObjectName(QString::fromUtf8("groupBox"));
        verticalLayout = new QVBoxLayout(groupBox);
        verticalLayout->setObjectName(QString::fromUtf8("verticalLayout"));
        randomList = new QListWidget(groupBox);
        randomList->setObjectName(QString::fromUtf8("randomList"));

        verticalLayout->addWidget(randomList);


        horizontalLayout_3->addWidget(groupBox);

        groupBox_2 = new QGroupBox(widget);
        groupBox_2->setObjectName(QString::fromUtf8("groupBox_2"));
        horizontalLayout = new QHBoxLayout(groupBox_2);
        horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout"));
        bubbleList = new QListWidget(groupBox_2);
        bubbleList->setObjectName(QString::fromUtf8("bubbleList"));

        horizontalLayout->addWidget(bubbleList);


        horizontalLayout_3->addWidget(groupBox_2);

        groupBox_3 = new QGroupBox(widget);
        groupBox_3->setObjectName(QString::fromUtf8("groupBox_3"));
        horizontalLayout_2 = new QHBoxLayout(groupBox_3);
        horizontalLayout_2->setObjectName(QString::fromUtf8("horizontalLayout_2"));
        quickList = new QListWidget(groupBox_3);
        quickList->setObjectName(QString::fromUtf8("quickList"));

        horizontalLayout_2->addWidget(quickList);


        horizontalLayout_3->addWidget(groupBox_3);


        verticalLayout_2->addWidget(widget);

        startBtn = new QPushButton(centralwidget);
        startBtn->setObjectName(QString::fromUtf8("startBtn"));

        verticalLayout_2->addWidget(startBtn);

        MainWindow->setCentralWidget(centralwidget);
        menubar = new QMenuBar(MainWindow);
        menubar->setObjectName(QString::fromUtf8("menubar"));
        menubar->setGeometry(QRect(0, 0, 800, 26));
        MainWindow->setMenuBar(menubar);
        statusbar = new QStatusBar(MainWindow);
        statusbar->setObjectName(QString::fromUtf8("statusbar"));
        MainWindow->setStatusBar(statusbar);

        retranslateUi(MainWindow);

        QMetaObject::connectSlotsByName(MainWindow);
    } // setupUi

    void retranslateUi(QMainWindow *MainWindow)
    {
        MainWindow->setWindowTitle(QCoreApplication::translate("MainWindow", "MainWindow", nullptr));
        groupBox->setTitle(QCoreApplication::translate("MainWindow", "\351\232\217\346\234\272\346\225\260", nullptr));
        groupBox_2->setTitle(QCoreApplication::translate("MainWindow", "\345\206\222\346\263\241\346\216\222\345\272\217", nullptr));
        groupBox_3->setTitle(QCoreApplication::translate("MainWindow", "\345\277\253\351\200\237\346\216\222\345\272\217", nullptr));
        startBtn->setText(QCoreApplication::translate("MainWindow", "\345\274\200\345\247\213", nullptr));
    } // retranslateUi

};

namespace Ui {
    class MainWindow: public Ui_MainWindow {};
} // namespace Ui

QT_END_NAMESPACE

#endif // UI_MAINWINDOW_H

第二种方式:继承QObject对象

mainwindow.cpp

#include "mainwindow.h"
#include "mythread.h"
#include "ui_mainwindow.h"
#include <QLabel>
#include <QPushButton>
#include <QThread>

MainWindow::MainWindow(QWidget* parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //创建子线程

    Generate* gen = new Generate;
    Quicksort* quick = new Quicksort;
    Bubblesort* bubble = new Bubblesort;
    //创建任务类
    QThread* thread1 = new QThread;
    QThread* thread2 = new QThread;
    QThread* thread3 = new QThread;
    //将任务对象移入
    gen->moveToThread(thread1);
    quick->moveToThread(thread2);
    bubble->moveToThread(thread3);

    connect(this, &MainWindow::starting, gen, &Generate::working);

    connect(ui->startBtn, &QPushButton::clicked, this, [=]() {
        emit this->starting(10000);        //启动线程
        thread1->start(); });

    //接受数据
    connect(gen, &Generate::sayNum, quick, &Quicksort::working);
    connect(gen, &Generate::sayNum, bubble, &Bubblesort::working);
    //    connect(gen, &Generate::sayNum, this, [=](QVector<int> v) {
    //        quick->working(v);
    //        bubble->working(v);
    //    }); //错误写法,在主线程运行了

    //接受数据
    connect(gen, &Generate::sayNum, this, [=](QVector<int> v) {
        //接收到数据证明程序已经启动了 ,
        thread2->start();
        thread3->start();
        //显示
        for (int i = 0; i < v.size(); ++i) {
            ui->randomList->addItem(QString::number(v.at(i)));
        }
    });
    //冒泡
    connect(bubble, &Bubblesort::finish, this, [=](QVector<int> v) {
        //        qDebug()<<"冒泡显示";
        //接收到数据证明程序已经启动了
        for (int i = 0; i < v.size(); ++i) {
            ui->bubbleList->addItem(QString::number(v.at(i)));
        }
    });

    //    //快排序
    connect(quick, &Quicksort::finish, this, [=](QVector<int> v) {
        //接收到数据证明程序已经启动了 ,
        //        qDebug() << "内置排序";
        for (int i = 0; i < v.size(); ++i) {
            ui->quickList->addItem(QString::number(v.at(i)));
        }
    });
    connect(this, &QWidget::destroyed, this, [=]() {
        thread1->quit();
        thread1->wait();
        thread1->deleteLater();

        thread2->quit();
        thread2->wait();
        thread2->deleteLater();

        thread3->quit();
        thread3->wait();
        thread3->deleteLater();
    });
}

void MainWindow::subThread()
{
    int num = 0;
    while (1) {
        num++;
        if (num == 100000) {
            break;
        }
        label->setText(QString::number(num));
        QThread::sleep(1);
    }
}

MainWindow::~MainWindow()
{
    delete ui;
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QLabel>
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow {
    Q_OBJECT

public:
    MainWindow(QWidget* parent = nullptr);
    ~MainWindow();
    void subThread();
    QLabel* label;

private:
    Ui::MainWindow* ui;
signals:
    void starting(int num);
};
#endif // MAINWINDOW_H

线程池使用

继承QRunnable重写run方法,run方法是公共函数

thread.cpp

#include "mythread.h"
#include <QElapsedTimer>
#include <QObject>
#include <QRandomGenerator>
#include <QRunnable>
#include <QVector>

Generate::Generate(QWidget* parent)
    : QObject(parent)
    , QRunnable()
{
    setAutoDelete(true);
}
void Generate::run()
{
    qDebug() << "线程运行了,线程地址是" << QThread::currentThread();

    QVector<int> v;
    QElapsedTimer time;
    time.start();
    for (int i = 0; i < this->num; i++) {
        //        v.push_back(rand() % 10000);
        v.push_back(QRandomGenerator::global()->bounded(0, 1000));
    }
    int milsec = time.elapsed();
    qDebug() << "生成" << num << "个随机数"
             << "耗时" << milsec << "毫秒";
    emit this->sayNum(v);
}

void Generate::recvNum(int num)
{
    this->num = num;
}

//冒泡代码

Bubblesort::Bubblesort(QWidget* parent)
    : QObject(parent)
    , QRunnable()

{
    setAutoDelete(true);
}

void Bubblesort::recvArry(QVector<int> v)
{
    this->v = v;
}

void Bubblesort::run()
{

    QElapsedTimer timer;
    timer.start();
    //冒泡排序
    qDebug() << "冒泡" << QThread::currentThread();
    for (int i = 0; i < v.size(); ++i) {
        for (int j = 0; j < v.size() - i - 1; ++j) {
            if (v[j] > v[j + 1]) {
                int temp = v[j];
                v[j] = v[j + 1];
                v[j + 1] = temp;
            }
        }
    }
    int milsec = timer.elapsed();
    qDebug() << "冒泡耗时" << milsec << "毫秒";
    emit finish(v);
};

//快速排序
Quicksort::Quicksort(QWidget* parent)
    : QObject(parent)
    , QRunnable()

{
    setAutoDelete(true);
}

void Quicksort::recvArry(QVector<int> v)
{
    this->v = v;
}

void Quicksort::run()
{
    QElapsedTimer timer;
    timer.start();
    //快排序
    qDebug() << "快速排序" << QThread::currentThread();
    std::sort(v.begin(), v.end());

    int milsec = timer.elapsed();
    qDebug() << "快排耗时" << milsec << "毫秒";
    emit finish(v);
};

thread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QObject>
#include <QRunnable>
#include <QThread>
#include <QWidget>
class Generate : public QObject, public QRunnable {
    Q_OBJECT
public:
    explicit Generate(QWidget* parent = nullptr);
    void recvNum(int num);
    void run() override;

signals:
    void sayNum(QVector<int>);

protected:
private:
    int num;
};
//冒泡排序
class Bubblesort : public QObject, public QRunnable {
    Q_OBJECT
public:
    explicit Bubblesort(QWidget* parent = nullptr);
    void recvArry(QVector<int>);
    void run() override;

signals:
    void finish(QVector<int>);

private:
    QVector<int> v;
};
//快速排序

class Quicksort : public QObject, public QRunnable {
    Q_OBJECT
public:
    explicit Quicksort(QWidget* parent = nullptr);
    void recvArry(QVector<int>);
    void run() override;

signals:
    void finish(QVector<int>);

private:
    QVector<int> v;
};

#endif // MYTHREAD_H

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QLabel>
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow {
    Q_OBJECT

public:
    MainWindow(QWidget* parent = nullptr);
    ~MainWindow();
    void subThread();
    QLabel* label;

private:
    Ui::MainWindow* ui;
signals:
    void starting(int num);
};
#endif // MAINWINDOW_H

maindindow.cpp

#include "mainwindow.h"
#include "mythread.h"
#include "ui_mainwindow.h"
#include <QLabel>
#include <QPushButton>
#include <QThread>
#include <QThreadPool>
MainWindow::MainWindow(QWidget* parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //创任务类;

    Generate* gen = new Generate;
    Quicksort* quick = new Quicksort;
    Bubblesort* bubble = new Bubblesort;

    connect(this, &MainWindow::starting, gen, &Generate::recvNum);

    connect(ui->startBtn, &QPushButton::clicked, this, [=]() {
        emit this->starting(100000); //启动线程
        //        gen->start();
        QThreadPool::globalInstance()->start(gen);
    });
    //接受数据
    connect(gen, &Generate::sayNum, quick, &Quicksort::recvArry);
    connect(gen, &Generate::sayNum, bubble, &Bubblesort::recvArry);
    //接受数据
    connect(gen, &Generate::sayNum, this, [=](QVector<int> v) {
        //接收到数据证明程序已经启动了 ,
        //        quick->start();
        //        bubble->start();
        QThreadPool::globalInstance()->start(quick);
        QThreadPool::globalInstance()->start(bubble);

        //显示
        for (int i = 0; i < v.size(); ++i) {
            ui->randomList->addItem(QString::number(v.at(i)));
        }
    });
    //冒泡
    connect(bubble, &Bubblesort::finish, this, [=](QVector<int> v) {
        //        qDebug()<<"冒泡显示";
        //接收到数据证明程序已经启动了
        for (int i = 0; i < v.size(); ++i) {
            ui->bubbleList->addItem(QString::number(v.at(i)));
        }
    });

    //    //快排序
    connect(quick, &Quicksort::finish, this, [=](QVector<int> v) {
        //接收到数据证明程序已经启动了 ,
        //        qDebug() << "内置排序";
        for (int i = 0; i < v.size(); ++i) {
            ui->quickList->addItem(QString::number(v.at(i)));
        }
    });
}

void MainWindow::subThread()
{
    int num = 0;
    while (1) {
        num++;
        if (num == 100000) {
            break;
        }
        label->setText(QString::number(num));
        QThread::sleep(1);
    }
}

MainWindow::~MainWindow()
{
    delete ui;
}

QtConcurrent高级API使用

Concurrent是并发的意思,QtConcurrent是一个命名空间,提供了一些高级的 API,使得在编写多线程的时候,无需使用低级线程原语,如读写锁,等待条件或信号。使用QtConcurrent编写的程序会根据可用的处理器内核数自动调整使用的线程数。这意味着今后编写的应用程序将在未来部署在多核系统上时继续扩展。
简单的说,QtConcurrent::run()函数会在一个单独的线程中执行,并且该线程取自全局QThreadPool,该函数的返回值通过QFuture API提供。
请注意:该函数可能不会立即运行; 函数只有在线程可用时才会运行。
通过QtConcurrent::run()返回的QFuture不支持取消、暂停,返回的QFuture只能用于查询函数的运行/完成状态和返回值

QT4版本需要添加<QtCore>头文件 Qt5需要pro文件添加 QT+= concurrent

void MainWindow::btnClick(){
    qDebug()<<"点击";
//    Qwidget* parent =0;
//    QFuture<void>f1 = QtConcurrent::run(func,QString("aa"));
//    f1.waitForFinished();
#if 1

    QFuture<void>    future = QtConcurrent::run(this,&MainWindow::func,QString("aa"));
    QFuture<void> f2 =QtConcurrent::run(this,&MainWindow::func,QString("aaa"));
//    qDebug()<<"filesh";
//函数指针的一个实现   
 void (MainWindow::*f)(QString);
    f = &MainWindow::func;
    func("fdas");
    (this->*(f))("test");

//    QFuture<void> f1 =QtConcurrent::run(f,QString("aa"));
//    f1.waitForFinished();

    QByteArray bytearray = "hello world";
    QFuture<QList<QByteArray> > future1 = QtConcurrent::run(bytearray, &QByteArray::split, ' ');
    qDebug()<< future1.result();

#else
    QFuture < void > future =  QtConcurrent::run([=](){
        qDebug() <<"1"<< __FUNCTION__  << QThread::currentThreadId() << QThread::currentThread();
    });
    QFuture < void > future2 = QtConcurrent::run([=](){
        qDebug() <<"2 "<< __FUNCTION__  << QThread::currentThreadId() << QThread::currentThread();
    });
#endif

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值