QtConcurrent与多线程QThread的多线程性能

Multithreading performance of QtConcurrent Vs QThread with many threads

本文关键字:多线程 性能 QThread QtConcurrent      更新时间:2023-10-16

假设您的应用程序需要在多个线程中运行一个函数,这些线程的数量大于CPU内核/线程的数量。一种方法是使用QtConcurrent并设置最大线程数:

MyClass *obj = new MyClass;
QThreadPool::globalInstance()->setMaxThreadCount(30);
for(int i=0;i<30;i++)
    QtConcurrent::run(obj, &MyClass::someFunction);
另一种方法是使用moveToThread将多个对象移动到不同的线程:
for(int i=0;i<30;i++)
{
        MyClass *obj = new MyClass;
        QThread *th = new QThread();
        obj->moveToThread(th);
        connect(th, SIGNAL(started()), obj, SLOT(someFunction()) );
        connect(obj, SIGNAL(workFinished()), th, SLOT(quit()) );
        connect(th, SIGNAL(finished()), obj, SLOT(deleteLater()) );
        connect(th, SIGNAL(finished()), th, SLOT(deleteLater()) );
        th->start();
}

由于线程数大于CPU核数,运行时需要在不同核间切换线程。

问题是这两种方法是否有不同的性能?也就是说,QThread的开关与QtConcurrent::run的开关不同吗?

我同意第一个答案,但我想补充一点。

QThread是低级别的类,只运行操作系统特定的功能。QtConcurrent是什么?答案在Qt源代码中。

第一级:运行

QFuture<T> run(T (*functionPointer)())  
{
        return (new StoredFunctorCall0<T, T (*)()>(functionPointer))->start();
}
第二:

struct StoredFunctorCall0: public RunFunctionTask<T>    { ...
第三:

template <typename T>
class RunFunctionTaskBase : public QFutureInterface<T> , public QRunnable
{ ...

现在谈谈QRunnable。当我们用QThreadPool启动QRunnable时,我们这样做:

start()调用tryStart(), startThread()QThreadPoolThread一起操作(它是一个QThread子类),最后调用QThreadstart()

当然这条链不是完整的,路很长,不是吗?因此,据我所知,当我们使用抽象时,我们有抽象惩罚(QtConcurrentQThread有更大的惩罚),但最终结果是一样的,它是QThread

简短的回答:这取决于工作负载的性质/逻辑。

QtConcurrent运行一个线程池,它是一个更高级别的API ,不适合运行大量的阻塞操作:如果你做了很多阻塞操作,你很快就会耗尽池并使其他请求排队。在这种情况下,QThread(较低级别的构造)可能更适合于操作(每个都代表一个线程)。