常熟做网站价格wordpress 改变字体
在开发中不可避免的会遇到耗时操作、后台计算、异步任务等需求。此时,使用多线程编程便成为解决性能与响应式 UI 的关键手段。而 Qt 提供了两种主流的并发机制:
QThread:底层线程控制类,功能强大,适合复杂线程模型。
QtConcurrent:基于线程池的高级接口,简洁易用,适合并发任务调度。
虽然它们都可实现多线程任务,但各自适用的场景、易用性、控制粒度却有很大不同:
一、概览对比
| 项目 | QThread | QtConcurrent | 
|---|---|---|
| 所属模块 | QtCore | QtConcurrent | 
| 控制粒度 | 低层级(线程生命周期) | 高层级(任务并发) | 
| 线程管理 | 手动控制(start/exit) | 自动管理(线程池调度) | 
| 使用方式 | 继承/组合/ moveToThread() | 使用 QtConcurrent::run()启动任务 | 
| 支持信号槽 | ✅(需要事件循环) | ❌(任务线程中默认无事件循环) | 
| 可取消任务 | ✅ | ✅(需手动控制) | 
| 易用性 | 复杂 | 简单 | 
| 常见用途 | 长期驻留线程、线程间通信 | 并发处理、异步操作、批量计算 | 
二、QThread:强控制、适合长期任务
方式一:继承 QThread
class MyThread : public QThread {
protected:void run() override {// 自定义线程逻辑}
};
方式二:组合 QObject + moveToThread
Worker *worker = new Worker;
QThread *thread = new QThread;worker->moveToThread(thread);
connect(thread, &QThread::started, worker, &Worker::doWork);
thread->start();
特点
- 需要自己控制线程生命周期: - start()、- quit()、- wait()。
- 适合 UI 与线程交互(信号槽机制)。 
- 可以运行事件循环,处理定时器、socket、事件等。 
- 适合需要持久运行或复杂状态管理的后台任务。 
三、QtConcurrent:自动调度,适合短期任务
最常用的方式:QtConcurrent::run()
QtConcurrent::run([](){doHeavyWork();
});
支持绑定返回值和观察器
QFuture<QString> future = QtConcurrent::run([]() {return QString("Hello from thread");
});QFutureWatcher<QString> *watcher = new QFutureWatcher<QString>();
QObject::connect(watcher, &QFutureWatcher<QString>::finished, [=](){qDebug() << "Result:" << future.result();watcher->deleteLater();
});
watcher->setFuture(future);
特点
- 自动使用 - QThreadPool管理线程;
- 任务无需手动创建线程或事件循环; 
- 适合“函数级别”的并发调用; 
- 不适合需要线程交互或长期保持任务状态的场景。 
四、完整示例
4.1、非阻塞常见使用(推荐)
QFuture<QString> future = QtConcurrent::run([]() {QThread::sleep(2);return QString("任务完成");
});QFutureWatcher<QString>* watcher = new QFutureWatcher<QString>();
QObject::connect(watcher, &QFutureWatcher<QString>::finished, [=]() {QString result = future.result();  // ✅ 此时不会阻塞,因为已经 finishedqDebug() << "结果是:" << result;watcher->deleteLater();
});
watcher->setFuture(future);
4.2、非阻塞带返回值示例
既可以获取到返回值还可以防止任务重复运行
QFuture<int> future;
QFutureWatcher<int> watcher;void MyWorker::startTask()
{if (future.isRunning())return;future = QtConcurrent::run([]() -> int {QThread::sleep(2);return 42;});connect(&watcher, &QFutureWatcher<int>::finished, this, [=]() {qDebug() << "返回值为:" << future.result();});watcher.setFuture(future);
}
4.3、错误示例——阻塞获取数据
QFuture<QString> future = QtConcurrent::run([]() {QThread::sleep(5); // 模拟耗时任务return QString("Done");
});QString result = future.result(); // ⛔ 阻塞:等待上面的任务执行完毕
QtConcurrent::run(...)会把 lambda 提交给线程池去执行(异步),主线程继续往下执行,执行到future.result(),但是任务还没跑完,结果还没出来;
Qt 的
QFuture::result()必须返回值,所以当前线程(比如主线程)就 阻塞等待,等线程池中的任务执行完成,把结果返回;
| 方法名 | 是否阻塞 | 说明 | 
|---|---|---|
| future.result() | ✅ 会阻塞 | 阻塞直到任务完成并返回结果 | 
| future.waitForFinished() | ✅ 会阻塞 | 阻塞直到任务结束 | 
| future.isRunning() | ❌ 不阻塞 | 非阻塞方式判断任务是否仍在运行 | 
| future.isFinished() | ❌ 不阻塞 | 判断是否已完成 | 
| future.resultCount() | ❌ 不阻塞 | 并行结果数量(比如 mapped()) | 
| QFutureWatcher::finished()信号 | ❌ 不阻塞 | 信号通知,推荐 UI 中使用 | 
五、建议
- 不要滥用 QThread:不推荐直接在主线程中执行 - run();也不建议频繁创建/销毁线程。
- 短期任务用 QtConcurrent 更自然:能显著减少代码量,提高可读性。 
- 任务有 UI 回调?用 QFutureWatcher:避免在 - QtConcurrent的线程中直接访问 UI(线程不安全)。
- 需要信号槽?考虑 moveToThread 模式:结合事件循环,线程间通信更强大。 
- 并行计算/算法任务?可用 QtConcurrent::mapped/filter/reduce:实现更复杂的 Map-Reduce 模式。 
六、总结
QThread 和 QtConcurrent 都是 Qt 提供的强大多线程工具,但使用方式和适用范围不同。
- QThread更加底层、可控,适合复杂线程管理、线程间通信;
- QtConcurrent更简洁现代,适合并发计算与短时任务;
| 场景 | 推荐机制 | 理由 | 
|---|---|---|
| 文件/网络下载 | QThread | 需要事件循环、信号槽响应、状态控制 | 
| 图像处理/批量压缩 | QtConcurrent | 任务独立、计算密集、无需交互 | 
| 后台服务守护 | QThread | 线程常驻、需要持续响应 | 
| 数据库查询 | QtConcurrent | 一次性任务,避免阻塞 UI | 
| UI 按钮触发异步任务 | QtConcurrent | 简洁,方便绑定任务完成回调 | 
| 多任务调度/线程池复用 | QtConcurrent | 自动使用线程池,避免重复造轮子 | 
