0

好的,所以我问了几个关于 QFuture 的问题,这是我目前用来线程化我的 UI 应用程序的。

基本上我在一个需要很长时间的类中有一个函数,所以我自然希望它线程化,所以当从我的 UI 类调用它时,它不会只是锁定我的 UI。

然后我实现了一个 QFutureWatcher 来等待 finished() 信号,此时它将启动另一个函数,该函数在一个新线程中花费了很长时间(但是这个函数正在对 UI 做一些事情)。我使用相同的代码来实现第二个线程函数,但是这个函数仍然锁定了我的 UI。

我得出的结论可能完全错误,但我似乎无法找出为什么它不起作用所以我所能做的就是假设并在这里问......

也许我不能有 2 个使用 QConcurrentRun 的 QFuture

不能将 QFuture 与 ui 的东西一起使用(在我的情况下 QGraphicsView 添加到场景)

如果有人有很棒的建议,请在另一篇文章中阅读,我可能应该将 QObject 子类化,但没有给出示例,所以我无法真正实现这一点,因为我什至不知道我打算重新实现什么样的功能..

TLDR:如何线程化一个对 UI 起作用的函数(添加到 QGraphicsScene)

代码示例,这是一个需要很长时间的函数,因为我从不同的函数循环调用这个函数几十万次,大约需要 30 秒才能完成,此时 UI 没有响应

void GUI::paintSomething(double x, double y)
{
    /// Decalre a QPen for Painting dots
    QPen pen;

    // set the pen colour
    pen.setColor(Qt::white);

    // Add ellipse at the x y position passed in
    scene->addEllipse(x, y, 1.5, 1.5, pen, QBrush(Qt::SolidPattern));
}

线程代码,paint都是调用paintSomething的函数

*future2 = QtConcurrent::run(this, &GUI::paintAll);

// Set watcher to look at QFuture futre2
watcher2->setFuture(*future2);
4

2 回答 2

4

首先从除主线程之外的任何内容更新 ui / 创建 ui 元素是一个很大的禁忌。所以甚至不要走那条路。

要在工作线程和主线程之间进行通信,在 Qt 中,您可以Qt::QueuedConnection在连接跨线程 Signal <-> Slot 时使用。

您通常打算做的是在工作线程中进行计算,当您创建元素并将其添加到 时QGraphicsView,发送带有所需相关信息的信号,在主线程中捕获它并采取相应措施.

更新:

好吧,如果你调用任何东西“几十万次”,即使它是在大约 30 秒内从主线程调用单个函数,你也会有性能损失。这就是它归结为。解决这个问题没有什么神奇的技巧,因为你受限于你所拥有的硬件以及它在一个时钟周期内可以提供什么。

你需要的是用不同的方式解决你的问题。问问自己你QGraphicsView正在渲染什么。

是否可以将内容缓存到图像中?

是否所有的几十万个项目都需要可交互?

您还可以查看 Qt 附带的“Mandelbrot - 示例”以查看处理跨线程更新。

于 2013-04-24T16:05:26.303 回答
0

虽然这是非常糟糕的做法 - 从工作线程中更新 GUI 线程并且你应该通过信号槽来真正做到这一点,但你仍然可以通过以下方式更新 GUIQMetaObject::invokeMethod()

您必须在工作线程中运行每个函数,通过invokeMethod(). 例如 - 您void GUI::paintSomething(double x, double y)必须在线程中调用,如下所示:

QMetaObject::invokeMethod(this,"paintSomething", Q_ARG(double,x), Q_ARG(double,y));

GUI 会发现冻结,但这绝对不会提高您的性能..

i call this function from a different functions loop a few hundred thousand times

当我做类似的任务时——我没有在每次更新后更新 GUI,每秒只更新几次(QElapsedTimer)并且在 QImage 中完成了所有的绘画,在一些超时后在 QLabel 上重新绘画。希望这可以帮助

于 2013-04-24T19:06:16.290 回答