介绍
首先,我必须说这是针对在线游戏服务器完成的,该服务器会跟踪 map 中的每个对象,无论是玩家还是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值的函数。
每次调用更新时, map 对象必须检查是否有要添加到商店的新对象,如果添加了对象,则该对象必须通知所有其他对象已添加了该对象,我通过(伪代码)进行此操作:
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。

我的问题
还有其他优化方法吗?尽管我已经使用八叉树来跟踪对象在 map 中的位置,但是得出的结论是,这只会使问题变得更糟。
我还将每个 map 划分为实体的35个单位(35是“ View 范围”,LOS),以便给定的rde::hash_map仅包含彼此可见的单位,因此需要更新。只要对象数量少就可以工作...
我还能做什么?谢谢!

注意
所有这些foreach都是使用迭代器的循环,例如从rde::hash_map<...>::iteratorobjects.begin()objects.end()其他优化措施,例如在没有玩家的情况下不更新(真实用户,而不是NPC),在给定 map 上没有玩家的情况下释放内存,等等。

最佳答案

除了空间分割之外,想到的第一个优化是使对象仅被告知其附近的变化(例如四叉树),这是:是否必须向每个对象通知每个变化?为什么不告诉每个对象,“每一帧,我都会运行您的update方法。在update方法中,您可以查找所需的所有内容(例如,可能存在该帧/最近帧中发生的所有更改的缓冲区),并根据需要进行更新。这样,您无需花费CPU周期就可以将对象实际上不需要了解或关心的事情通知对象。

另外,您是否在程序上运行了CPU事件探查器,并验证了热点(花费最多的CPU时间)是否在您认为的位置?

请参阅评论以进行进一步讨论:

 |
 |
\|/
 V

09-28 13:31