【问题标题】:Iterating and storing thousands/millions of objects efficiently有效地迭代和存储数千/数百万个对象
【发布时间】:2013-02-14 20:57:42
【问题描述】:

我正在做一个模拟,我需要能够处理更新每个循环的数千个潜在的数百万个对象。 所有对象都需要具有称为(AI)的逻辑功能。 但是根据对象的位置决定了逻辑的详细程度。例如:

[使用 100 个对象保持简单]

  • 所有对象都有一个位置 (x,y)
  • 20 对象距离 500 点 从“兴趣点”位置。
  • 50 对象为 500 分 来自20 对象(1000 点外)。
  • 30 对象在 100 以内 从兴趣点出发。

现在说这是一个详细的城市模拟,对象是虚拟公民。 下午 6 点是每个人下班回家睡觉的时间。

所以我们遍历所有公民,但我希望他们做不同的事情。

  • 最远的物体 (50) 下班回家睡觉 直到早上。
  • 较近的物体 (20) 下班回家,有一个 吃点东西然后睡到早上。
  • 最近的物体 (30) 去 下班回家,吃点东西,刷牙然后睡觉直到 早上。

如您所见,它们越靠近兴趣点,逻辑就越详细。

我正在尝试找出迭代所有对象的最佳和最高效的方法。 用满手的物体这会相对容易,但由于这需要有效地处理至少 500,000 个物体,我需要一些建议。

此外,我不确定是否应该在每个循环中遍历所有对象,或者最好在每个循环中遍历最近的对象,但每 10 个循环仅遍历更远的对象?

由于需要对象在靠近它们的其他对象之间进行交互的额外要求,我一直在想最好的方法可能是将它们组织在四叉树中,但我不确定。似乎四叉树更适合静态内容,但我正在处理的对象,如前所述,有一个位置,需要移动到其他位置。 我是否走在正确的思考轨道上?还是有“更好”的方法?

如果有人认为它相关,我也在使用 c++。

任何建议将不胜感激。

注意:

  1. 兴趣点定期变化,把它想象成一个相机 查看。
  2. 对象是动态创建和销毁的

【问题讨论】:

    标签: loops iteration quadtree


    【解决方案1】:

    如果您想从特定点快速选择特定半径内的对象,那么四叉树或简单的方形网格会有所帮助。

    如果您的问题是如何存储数百万个对象以提高迭代效率,那么您可能可以使用基于列的技术,而不是拥有 100 万个对象,每个对象有 5 个字段,而是有 5 个数组,每个数组包含 100 万个元素.在这种情况下,每个对象只是范围 0 .. 999999 中的一个索引。因此,例如,您要存储 100 万个具有以下结构的对象:

    struct resident
    {
        int x;
        int y;
        int flags;
        int age;
        int health; // This is computer game, right?
    }
    

    然后,您声明 5 个数组,而不是声明 resident residents [1000000]

    int resident_x [1000000];
    int resident_y [1000000];
    int resident_flags [1000000];
    int resident_age [1000000];
    int resident_health [1000000];
    

    然后,你使用resident_x [n] 代替residents [n].x。当您需要遍历所有相同类型的对象并对每个对象中的几个字段(每个对象中具有相同的字段集)执行某些操作时,这种存储对象的方式可能会更快。

    【讨论】:

    • 所以阵列一将最接近点,阵列二将是下一个最接近的...然后根据对象与该点的距离在阵列之间移动对象?唯一忘记提的问题是兴趣点发生了变化,所以会有很多数组交换。
    • @xyz 没有。刚刚添加了更多详细信息。
    • 对不起,我错过了理解。感谢您为我解决这个问题。
    • 我以前从来没有遇到过这个解决方案,你有什么文章可以指导我到哪里可以阅读更多关于这个的信息吗?我有点怀疑拥有多个阵列如何更快。是不是没有物体可以让这个速度更快?
    【解决方案2】:

    您需要将问题分解为“类”,就像在现实世界中一样。每个人的班级都是根据距离计算的。所以下层人远,上层人近。或者更准确地说是“远类”、“近类”和“这里类”或任何你想命名的名称。

    1) 为每个类创建一个包含一个插槽的数组。该插槽将保存该班级中每个人的“链接列表”。当一个人的类别改变者(社会攀登者)时,将对象移动到另一个列表是非常迅速的。

    2) 所以把每个人都放到适当的类中,只迭代你附近的类。在适当的情况下,有些对象需要关心很远,因此您可以将它们放回磁盘并仅在您靠近时重新加载。

    【讨论】:

    • 我不知道计算时间是否有益?作为每个循环,我需要检查所有对象类关联,以确保它们仍然属于正确的类,如果不更改它们的类。 for(i=0;i<n;i++) if(citizen[i]->class == far && citizen[i]->distance >= 1000) continue; else.... 除非我缺少什么?
    • 分配距离或班级时是否更改班级。不在循环中。因此,当您设置距离或该类创建一个名为更新类的函数并在那里检查它时。因为列表是链接的,所以切换类很快。
    • 是的,使用链表,没有 i 整数的 for 循环。使用链表循环它。它必须是一个链表,以便可以快速更改类。
    【解决方案3】:

    里面有几个问题: -如何处理大量的物体?如果有固定数量的固定对象,只要您有足够的内存,您就可以简单地创建它们的数组。如果您需要动态地创建和销毁它们,那么如果没有仔细处理被销毁的对象,您就会面临内存泄漏的风险。在某个时候,您可能会问自己,使用其他应用程序(例如数据库)来存储对象并仅执行 C++ 代码中的逻辑是否更好。数据库将提供我将重点介绍的其他功能。

    -如何在给定距离内找到与他人相距的物体。这是地理信息系统(GIS)的经典问题;听起来您正在尝试操作一个简单的 GIS 来存储您的对象和属性,因此它是适用的。在每个点上测试距离公式 SQRT((X-x)^2+(Y-y)^2) 需要计算能力。相反,通常使用“窗口函数”来提取包含您想要的所有点的正方形,然后在其中搜索以查找特定位于给定半径内的点。一些数据库经过优化以执行各种 GIS 功能,包括返回给定半径内的点,或返回一些其他几何形状(如多边形)内的点。否则,您必须自己编写此功能。

    -对象的树存储。这可以提高速度,但是如果对象不断地四处移动,您将需要权衡,其中必须经常重组树。这完全取决于事物移动的频率与您希望对其进行计算的频率。

    -AI 代码。如果您尝试对数百万个对象进行 AI,这可能是您对性能的最大使用,而不是用于存储和搜索对象的方法。你是对的,对于更远的点,更简单的代码会提高性能,对于更远的点执行逻辑的频率也会降低。这有时使用蒙特卡洛分析来处理,其中逻辑将在任何给定迭代期间对点的随机子集执行,并且随着与感兴趣点的距离增加,执行的概率可能会降低。

    【讨论】:

      【解决方案4】:

      我会考虑使用带有 Morton 编码/Z-Order 索引的线性四叉树。您可以通过使用位数组来表示包含数据并非常快速地执行计算的节点来进一步优化此结构。

      我使用 Javascript 在浏览器中非常高效地完成了这项工作,并且可以在亚秒内遍历 6700 万个节点。一旦我将其缩小到感兴趣的区域,我就会以不同的结构查找数据。所有这一切仍以毫秒为单位。我将它用于空间矢量动画。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-02-26
        • 2013-06-10
        • 2021-01-03
        • 2014-02-24
        • 2019-10-28
        • 1970-01-01
        • 2014-03-18
        • 2016-04-26
        相关资源
        最近更新 更多