Qt使用信号槽传递大量数据的效率问题

1. 隐式共享

之前一直担心Qt中的信号槽在传递大量数据下的情况下复制拷贝产生的效率问题,还转而使用指针去传递。实际上因为Qt中的隐式共享的技术完全不用担心此问题。不过值得注意的是隐式共享的条件和使用规则,而且也并非所有的结构都支持隐式共享。

#include <QCoreApplication>
#include <QDebug>

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

    QByteArray b1 = "hello world";
    QByteArray b2 = b1;

    qDebug() << "0x" + QString::number(reinterpret_cast<qintptr>(b1.constData()),16);
    qDebug() << "0x" + QString::number(reinterpret_cast<qintptr>(b2.constData()),16);

    b2 = "你好,世界";

    qDebug() << Qt::endl;
    qDebug() << "0x" + QString::number(reinterpret_cast<qintptr>(b1.constData()),16);
    qDebug() << "0x" + QString::number(reinterpret_cast<qintptr>(b2.constData()),16);

    return a.exec();
}

输出:

"0x1b6558"
"0x1b6558"

"0x1b6558"
"0x1b7d68"

这里定义了两个变量,当把b1直接复制给b2时采用浅拷贝,两个变量的数据地址相同。修改b2的内容时,采用深拷贝。

2.信号槽中的隐式共享

#include <QCoreApplication>
#include <QDebug>

class Test : public QObject {
    Q_OBJECT
public:
    void received(QByteArray byte) {
        qDebug() << Q_FUNC_INFO << "0x" + QString::number(reinterpret_cast<qintptr>(byte.constData()),16);
        byte = "x";
        qDebug() << Q_FUNC_INFO << "0x" + QString::number(reinterpret_cast<qintptr>(byte.constData()),16);
    }

signals:
    void sigByte(QByteArray byte);
};

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

    QByteArray b1 = "hello world";
    qDebug() << Q_FUNC_INFO << "0x" + QString::number(reinterpret_cast<qintptr>(b1.constData()),16);

    Test t;
    QObject::connect(&t,&Test::sigByte,&t,&Test::received);

    emit t.sigByte(b1);

    return a.exec();
}

#include "main.moc"

输出:

int main(int, char**) "0xf66558"
void Test::received(QByteArray) "0xf66558"
void Test::received(QByteArray) "0xf67df8"

同理信号槽中也是可以使用隐式共享的,其效果也是一样的。所以根本不用担心信号槽中传输大量数据下的效率问题。

3.多线程中信号槽的隐式共享

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

class Test : public QObject {
    Q_OBJECT
public:
    void received(QByteArray byte) {
        qDebug() << QThread::currentThread() << Q_FUNC_INFO << "0x" + QString::number(reinterpret_cast<qintptr>(byte.constData()),16);
        byte = "x";
        qDebug() << QThread::currentThread() << Q_FUNC_INFO << "0x" + QString::number(reinterpret_cast<qintptr>(byte.constData()),16);
    }

signals:
    void sigByte(QByteArray byte);
};

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

    QByteArray b1 = "hello world";
    qDebug() << QThread::currentThread() << Q_FUNC_INFO << "0x" + QString::number(reinterpret_cast<qintptr>(b1.constData()),16);

    Test t;
    QObject::connect(&t,&Test::sigByte,&t,&Test::received);

    QThread th;
    t.moveToThread(&th);
    th.start();

    emit t.sigByte(b1);

    return a.exec();
}

#include "main.moc"

输出:

QThread(0xdd5ff0) int main(int, char**) "0xdd6558"
QThread(0x69fd60) void Test::received(QByteArray) "0xdd6558"
QThread(0x69fd60) void Test::received(QByteArray) "0x2593a48"

可以看到多线程中信号槽的数据传递也是支持隐式共享的。

4.结论

无论是多线程还是单线程中信号槽的数据传递都是支持隐式共享的,所以也不用担心大数据下的效率问题。
不过笔者这里只试验了QByteArray,未对其它数据结构验证,使用时请先查看Qt官方手册或自行测试。
建议在不需要进行数据更改的地方使用常引用const QByteArray&的方式传递,这样在信号槽的直接连接时构造临时变量的开销也可以省掉。
多线程中也可以使用常引用的方式传递,因为是异步通信,Qt会在信号传递时生成临时变量,不过内部数据依然是浅拷贝不需要担心。在数据没有被任何变量引用时进行析构。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值