有效地迭代大量数据

时间:2013-06-04 23:47:13

标签: c++ loops data-structures iterator processing-efficiency

简介

首先,我必须说这是针对在线游戏服务器进行的,它可以跟踪地图中的每个对象,无论是玩家还是AI(NPC,或者你想要调用它)。

它不仅要跟踪它们,还要通知玩家近距离玩家。我已经解决了这个问题,而且我目前正在使用多线程方法,这种方法非常有效。

我的问题

我将所有对象存储在哈希表中。我们可以认为哈希表是unordered_map,虽然我实际上使用rde::hash_map,因为它在插入和获取(自测试)时更快,但需要更多RAM(不是现在问题。)

问题是,该映射存储对象的唯一ID(64位),加上对象指针,如: rde::hash_map<UInt64, Object*>

我的问题是:

我的应用程序(服务器)必须在一个循环(在一个线程内)中运行,这个循环必须每隔约50ms调用一次,以保持运行顺畅。循环代码如下所示:

void loop()
{
    UInt32 prev = clock();
    UInt32 prevSleep = 0;
    while (1)
    {
        UInt32 diff = clock() - prev;
        prev = clock();

        maps.update() // Suppose map is a class, which stores the objects map

        if (diff <= 50 + prevSleep)
        {
            prevSleep = 50 + prevSleep - diff;
            sleep(prevSleep);
        }
        else
            prevSleep = 0;
    }
}


现在,到目前为止,函数map::update()是导致循环增加到4500ms的函数。

每次调用更新时,映射对象都必须检查要添加到存储的新对象,如果添加了一个对象,该对象必须通知所有其他对象,我这样做(伪代码) :

foreach obectsToBeAdded as joiner:
    foreach objectsList as object:
        joiner->notify(object);
        object->notify(joiner);

稍后,必须调用每个对象的内部更新,我这样做(再次伪代码):

foreach objectsList as object:
    object->update();

而且,如果这还不够,上面的循环必须扩展为:

foreach objectsList as object:
    object->update()

    // Visit all the other objects
    // Called once every 1 sec for the object, not on every call
    foreach objectsList as other:
        if other != object:
            object->visit(other)


我尝试优化

将第一个循环(添加和通知)与更新循环合并,如下所示:

foreach objectsList as object:
    foreach objectsToBeAdded as joiner:
        object->notify(joiner)
        joiner->notify(object)

    object->update()

    // Called once every 1 sec for the object, not on every call
    foreach objectsList as other:
        if other != object
            object->visit(other)


当对象计数不大时,这种方法很有效,一旦增加,循环开始需要4秒,这远远超过我正在寻找的50ms。

我的问题

还有其他方法可以进一步优化吗?我虽然使用八叉树来跟踪地图中的物体位置,但后来得出的结论是它只会使问题恶化。

我还将每个地图划分为一个实体的35个单位(35个是&#34;视图范围&#34;,LOS),因此给定的rde::hash_map仅包含相互看见,因此需要更新。只要对象数量很少就可以工作......

我还能做什么?谢谢!



注意

所有这些foreach都是使用迭代器的循环,例如rde::hash_map<...>::iteratorobjects.begin()的{​​{1}}

其他优化,例如不更新,如果没有玩家(真实用户,而不是NPC),在没有玩家在给定地图上时释放内存,等等,已经被考虑在内

1 个答案:

答案 0 :(得分:1)

除了空间分割之外,首先想到的优化是因为对象仅被告知它们附近的变化(例如使用四叉树):每个对象都必须被告知每次变化吗?为什么不告诉每个对象,'每一帧,我都会运行你的update方法。在update方法中,您可以查找所需的所有内容(例如,可能存在此帧/最近帧中发生的所有更改的缓冲区)并根据您的需要自行更新。这样,您就不会花费CPU周期来通知对象他们实际上不需要知道或关心的事情。

另外,您是否在程序中运行了CPU分析器,并验证了热点(最耗费CPU时间的地方)是您认为的位置?

请参阅意见以获得进一步讨论:

 |
 |
\|/
 V