gpt4 book ai didi

c++ - Qt Slots 调用过于频繁

转载 作者:行者123 更新时间:2023-11-28 02:14:04 24 4
gpt4 key购买 nike

我有一个工作线程可以处理繁重且长时间的计算(最多十分之一秒)。这些计算产生数千个 QLine s,代表动态生长树的边。这些边可以随时修改,因为它们通过检查以距离表示的成本来连接树的节点。我想要包含边缘的 QGraphicsScene 的平滑更新。我尝试了信号和插槽:

  • 工作线程发出一个信号,所以当缓冲区已满时,这个信号会被主线程捕获,这将处理线的更新/绘制
  • 这个信号仍然被主线程捕获,但它似乎经常发出,所以 QGraphicsViewQLine 呛到待补充
  • 改变缓冲区的大小无关紧要
  • 是否有替代方法?

主要插槽是:

void MainWindow::update_scene(bufferType buffer)
{
for (int i = 0; i < buffer.size(); ++i)
{
if (buffer[i].first < (g_edges.size() - 1))
{
delete g_edges[buffer[i].first];
g_edges[buffer[i].first] = scene->addLine(buffer[i].second);
}
else
g_edges.push_back(scene->addLine(buffer[i].second));
}
}

请注意 bufferType类型为 QList<std::pair<int,QLine>> .这是重计算部分

while (T.size() < max_nodes_number && !_stop)
{
const cnode random_node = rand_conf ();
const cnode nearest_node = T.nearest_node (random_node);
cnode new_node = new_conf (nearest_node, random_node);

if (obstacle_free(nearest_node, new_node))
{
QList<cnode*> X_near = T.neighbours (new_node, max_neighbour_radius);
cnode lowest_cost_node = nearest_node;
qreal c_min = nearest_node.cost() + T.distance (nearest_node, new_node);

for (int j = 0; j < X_near.size(); ++j)
{
if (obstacle_free(*X_near[j], new_node) && ((X_near[j]->cost() + T.distance (*X_near[j], new_node)) < c_min))
{
c_min = X_near[j]->cost() + T.distance (*X_near[j], new_node);
lowest_cost_node = *X_near[j];
}
}

T.add_node (new_node, lowest_cost_node.id());
queue (new_node.id(), QLine (new_node.x(), new_node.y(), lowest_cost_node.x(), lowest_cost_node.y()));

for (int j = 0; j < X_near.size(); ++j)
{
if (obstacle_free(*X_near[j], new_node) && (new_node.cost() + T.distance (new_node, *X_near[j])) < X_near[j]->cost())
{
queue (X_near[j]->id(), QLine (new_node.x(), new_node.y(), X_near[j]->x(), X_near[j]->y()));

T.update_parent (*X_near[j], new_node.id());
T.rewire_tree (X_near[j]->id());
}
}
}
}
emit finished();

请注意T是代表树的类。它由一些允许添加节点、搜索最近的节点等方法构成。它有一个 QList<cnode>。作为私有(private)成员,存储树的节点。 cnode是一个由两个坐标组成的结构,一个id,一个parent,一个cost,一个它的children的列表。

最佳答案

解决方案与往常一样 - 避免频繁排队连接,因为它们非常慢。排队连接是一种粗粒度结构,因此可以这样使用。

批处理工作。在您的场景中,您可以将计算出的线条聚合到一个容器中,只有当它达到某个阈值时,才将该容器传递给主线程以绘制/更新线条。阈值可以是计数、时间或两者的组合,如果只有少数结果要更新,您不希望不更新。您将需要扩展您的设计以拆分 while 循环以在线程事件循环中运行而不是阻塞,这样您就可以定期聚合和传递更新 - 类似于 this .对于需要时间的工作人员来说,这总是一个好主意 - 您可以监控进度、取消、暂停和各种方便的东西。

那两行看起来很可疑:

    edges.removeAt(i);
edges.insert (i, scene->addLine (l));

然后您删除然后插入 - 这是潜在的昂贵重新分配的邀请,即使没有重新分配也涉及不必要的复制。您可以简单地替换该索引处的元素,而不是删除和插入。

在您的情况下,您可能会忽略拆分实际的 while 循环。只是不要在循环中发出,而是做这样的事情(伪代码):

while(...) {
...
queue(new line)
...
queue(update line)
...
queue(final flush)
}

void queue(stuff) {
stuffBuffer.append(stuff)
if (stuffBuffer.size() > 50 || final_flush) {
emit do_stuff(stuffBuffer) // pass by copy
stuffBuffer.clear() // COW will only clear stuffBuffer but not the copy passed above
}
}

或者如果它会让你感觉更好:

    copy = stuffBuffer
stuffBuffer.clear()
emit do_stuff(copy)

通过这种方式,两个容器在发出拷贝之前与共享数据分离。

编辑:经过长时间的讨论,我最终提出了一些设计更改以提高性能(排队的连接只是性能问题的一个方面):

  • 减轻图形场景 - 在“每行一个项目”和“所有行一个项目”解决方案之间找到折衷方案,其中每个项目处理其直接子项的线条绘制,平衡 CPU 时间用于将项目添加到场景并在数据更改时重绘项目。

  • 禁用自动场景更新,而是显式控制场景更新,这样场景就不会针对每个微小的变化进行更新。

  • 批量聚合 View 命令并以固定间隔提交工作缓冲区以避免排队信号开销。

关于c++ - Qt Slots 调用过于频繁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34582612/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com