18

假设您的应用程序需要在多个线程中运行一个函数,其数量多于 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 内核数,因此在运行时应在不同内核之间切换线程。

问题是这两种方法是否有不同的表现?即 a 的切换QThread与使用 运行的不同QtConcurrent::run吗?

4

2 回答 2

17

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

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. 当我们开始时QRunnableQThreadPool我们这样做:

start()调用哪个调用哪个tryStart()调用(它是QThread 子类),最后是.startThread()QThreadPoolThreadstart()QThread

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

于 2015-06-06T08:28:37.330 回答
11

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

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

于 2015-06-06T08:05:43.363 回答