QThread 总是留下一个线程
QThread always one thread left behind
这是我的帖子:
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
.
程序每次运行时,四个线程的启动时间都差不多。但是总有一个线程 return 慢得多。例如,前 3 个线程完成大约需要 2 分钟,第四个线程可能需要 5 分钟才能完成 return。
但是所有线程都应该有相同数量的项目和相同的计算复杂度。
为什么总有话题落下?
调试输出:
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
"Why is there always a thread left behind?"
为什么不呢?线程调度完全是OS的心血来潮。根本无法保证任何线程都将获得任何 CPU 资源的任何类型的 "fair share"。您需要分配小块工作并让它们自动分布在工作线程中。 QtConcurrent::run
和 QtConcurrent 框架通常提供了一种简单的方法来完成这项工作。只要传递给 run
、mapReduce
等的工作块大小合理(比如在 0.1 到 1 秒之间),池中的所有线程都将在十分之几内完成每个一秒钟。
对您观察到的行为的部分解释是,已经 运行 在给定核心上的线程更有可能在同一核心上重新安排,以利用那里的热缓存。如果四个核心中有三个 运行 您的线程几乎不间断运行,则第四个线程通常最终会与您的 GUI 线程共享核心,并且如果 GUI 不空闲,则必然会 运行 变慢。如果 GUI 线程正忙于处理来自其他线程的结果,那么计算线程在该核心上会饿死就不足为奇了。这实际上是最强大的 - 和 最省时的线程调度方式,开销最少。
只要您给线程小块工作,并在准备就绪的基础上分配它们 - 正如 QtConcurrent
所做的那样 - 它也会导致最小的挂钟 运行 次.如果调度程序强制 "fair" 重新安排,您的 long-运行ning 线程将大致同时完成,但需要更多时间 and power 才能完成工作。现代调度程序使您能够最有效地 运行 您的作业,但您必须设置作业以利用它。
在某种程度上,您的调度程序正在帮助您改进代码以提高资源效率。这是好事。
这是我的帖子:
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
.
程序每次运行时,四个线程的启动时间都差不多。但是总有一个线程 return 慢得多。例如,前 3 个线程完成大约需要 2 分钟,第四个线程可能需要 5 分钟才能完成 return。
但是所有线程都应该有相同数量的项目和相同的计算复杂度。
为什么总有话题落下?
调试输出:
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
"Why is there always a thread left behind?"
为什么不呢?线程调度完全是OS的心血来潮。根本无法保证任何线程都将获得任何 CPU 资源的任何类型的 "fair share"。您需要分配小块工作并让它们自动分布在工作线程中。 QtConcurrent::run
和 QtConcurrent 框架通常提供了一种简单的方法来完成这项工作。只要传递给 run
、mapReduce
等的工作块大小合理(比如在 0.1 到 1 秒之间),池中的所有线程都将在十分之几内完成每个一秒钟。
对您观察到的行为的部分解释是,已经 运行 在给定核心上的线程更有可能在同一核心上重新安排,以利用那里的热缓存。如果四个核心中有三个 运行 您的线程几乎不间断运行,则第四个线程通常最终会与您的 GUI 线程共享核心,并且如果 GUI 不空闲,则必然会 运行 变慢。如果 GUI 线程正忙于处理来自其他线程的结果,那么计算线程在该核心上会饿死就不足为奇了。这实际上是最强大的 - 和 最省时的线程调度方式,开销最少。
只要您给线程小块工作,并在准备就绪的基础上分配它们 - 正如 QtConcurrent
所做的那样 - 它也会导致最小的挂钟 运行 次.如果调度程序强制 "fair" 重新安排,您的 long-运行ning 线程将大致同时完成,但需要更多时间 and power 才能完成工作。现代调度程序使您能够最有效地 运行 您的作业,但您必须设置作业以利用它。
在某种程度上,您的调度程序正在帮助您改进代码以提高资源效率。这是好事。