这是我的主题:
class calThread : public QThread
{
Q_OBJECT
public:
calThread(QList<int> number);
~calThread();
void run();
QList<int> cal(QList<int> input);
signals:
void calFinished(QList<int> result);
};
void calThread::run()
{
output = cal(number);
emit calFinished(output);
sleep(1);
}
这就是我调用线程的方式:
calThread* worker3 = new calThread(numberList);
connect(worker3, SIGNAL(calFinished(List<int>)), this, SLOT(handleResult(List<int>)));
connect(worker3, SIGNAL(finished()), worker3, SLOT(deleteLater()));
worker3->start();
我有一大堆输入。我将列表分成四个相等大小的列表,并将它们放入单独的线程中进行计算。它们是worker0
到worker3
。
每次程序运行时,四个线程都会在相似的时间开始。但是总有一个线程返回得慢得多。例如,前3个线程完成需要大约2分钟,第四个线程可能需要5分钟才能完成。
但是所有线程都应该具有相同数量的项目和相同的复杂度来计算。
为什么总会留下一个线索?
inputThread0 item numbers: 1736
inputThread1 item numbers: 1736
inputThread2 item numbers: 1736
inputThread3 item numbers: 1737
"20:29:58" Thread 0 Thread ID 0x7f07119df700
"20:29:58" Thread 3 Thread ID 0x7f06fc1d3700
"20:29:58" Thread 1 Thread ID 0x7f06fd1d5700
"20:29:58" Thread 2 Thread ID 0x7f06fc9d4700
"20:29:58" Thread 0 Thread ID 0x7f07119df700
"20:29:58" Thread 1 Thread ID 0x7f06fd1d5700
….............................
//Most of them are Thread 0,1,2 afterward
….............................
"20:29:58" Thread 1 Thread ID 0x7f06fd1d5700
// This is last Thread from thread 0,1,or2
// It takes less than one second to finish
"20:29:59" Thread 3 Thread ID 0x7f06fc1d3700
"20:29:59" Thread 3 Thread ID 0x7f06fc1d3700
"20:29:59" Thread 3 Thread ID 0x7f06fc1d3700
"20:29:59" Thread 3 Thread ID 0x7f06fc1d3700
….................................
// Only Thread 3 left
"20:30:17" Thread 3 Thread ID 0x7f06fc1d3700
// This last thread takes 19 second to finish
答案 0 :(得分:4)
“为什么总会留下一个线索?”
为什么不呢?线程调度完全是OS的一时兴起。根本不能保证任何线程都能获得任何CPU资源的“公平份额”。您需要分配一小部分工作并让它们自动分布在工作线程中。 QtConcurrent::run
和QtConcurrent框架总体上提供了一种简单的方法来完成这项工作。只要传递给run
,mapReduce
等的工作块的大小合理(比如在0.1和1之间),池中的所有线程都将在十分之几的时间内完成。每一个中的第二个。
对您观察到的行为的部分解释是,已经在给定核心上运行的线程更有可能在同一核心上重新调度以利用那里的热缓存。如果四个核心中有三个几乎连续运行您的线程,则第四个线程通常最终会与您的GUI线程共享核心,如果GUI没有空闲,则必然会运行得更慢。如果GUI线程正在忙于处理来自其他线程的结果,那么计算线程将在该核心上处于饥饿状态并不出乎意料。这实际上是调度线程的最强大的和时间效率方式,开销最小。
只要你给线程做一小部分工作,然后像QtConcurrent
那样准备好分发它们 - 它也会导致最小的挂钟运行时间。如果调度程序强制执行“公平”重新安排,那么长时间运行的线程将大致同时完成,但需要更多时间和才能完成工作。现代调度程序使您能够最有效地运行作业,但您必须设置作业以利用它。
在某种程度上,您的计划程序正在帮助您改进代码,从而提高资源效率。这是件好事。