使用 GUID 作为键缓存“深度”JSON 对象

Posted

技术标签:

【中文标题】使用 GUID 作为键缓存“深度”JSON 对象【英文标题】:Caching a "deep" JSON object using GUIDs as keys 【发布时间】:2014-11-13 02:30:05 【问题描述】:

所以我有一个从我的 javascript 应用程序中的 JSON 文件加载的大而简单的对象。

这个文件有大约 9 MB 的数据(不过,一旦我缩小它应该会更低)并且是这样的嵌套结构:


    "guid": "guid 1 here",
    "children": [
        
            "guid": "guid 2 here",
            "other": "properties",
            "here": true,
            "children": [
                
                    "guid": "guid 3 here",
                    ...
                ,
                ...
            ]
        ,
        ...
    ]

我不知道这个对象的深度,我需要使用一个通用函数来根据它的 GUID 属性定位一个节点,而不考虑它在树中的深度。这个递归函数(我知道可以使用 while 循环而不是递归进行优化,但不管它很昂贵)很慢。

我想知道是否最初在加载此对象后,我会创建一个这样的缓存结构:

var cache = 
    "guid 1 here": [reference to object],
    "guid 2 here": [reference to object],
    "guid 3 here": [reference to object]
;

我认为这样可以更快地找到对象,因为我只能说

var node = cache[guid];

但是,这实际上最终会提高性能,还是可能导致内存问题?我从未处理过像 cache 这样的变量,其中可能有数十万个属性。

这会帮助还是阻碍这种情况?

一如既往地感谢您的建议,所以,你们太棒了。

【问题讨论】:

@EdBayiates:不,数组在这里没用。 guid 不是数组索引,即使它们是数组也会非常稀疏(这不是一个好主意) 如果我使用数组,我是否必须遍历每个项目,直到找到具有所需 GUID 的项目? var result; for (var i = 0; i < cache.length; ++i) if (cache[i].guid == search_guid) result = cache[i]; break; 具有属性的对象是一个关联数组。抱歉,您上面的语法正确。所有 JavaScript 对象都在内部存储为数组,这就是 cache[guid] 起作用的原因。我编辑了答案以更新术语。 @EdBayiates: …一个没有顺序的关联数组,它留下一个哈希映射。它们是作为数组实现还是(更有可能)不是并不重要。 cache[guid] 不是数组语法,它是一个 object 属性访问。 是的。这就是您应该使用 varbatim 在不增加大量内存的情况下获得最佳性能的方法。 【参考方案1】:

你做出了正确的选择。

对象引用相当小。即使有数千个对象,这样的对象(在内部存储为类似数组的哈希映射)也不应该显着增加内存使用——最大几 MB。当您创建缓存时,您不会制作对象的副本。您正在将一个 pointer 放入对象(数组样式)中,该对象(数组样式)指向您已反序列化的结构中的对象。因此,您不会制作所有数据的第二份副本。只是一个 GUID 和指针的缓存。

这种缓存方法使用了 JavaScript 的一个很棒的特性,即属性索引在内部保持排序。然后使用二进制搜索执行按属性索引(例如 cache[guid] )的查找。这将比对未排序数据的循环或递归搜索快几个数量级。

【讨论】:

OP 没有使用数组作为缓存? []对象运算符吗? 您说的不是文字,而是查找运算符。【参考方案2】:

但是,这实际上最终会提高性能吗

大概吧。拥有一个大型的持续访问数据结构(即使构建成本很高)通常比重复迭代所有“数十万个”节点要快。

如果您可以优化递归查找功能,例如通过从 guid 派生父节点的位置,它可能没有那么大的好处。

或者这可能会导致内存问题?

是的,大型数据结构总是会导致内存不足的设备出现内存问题。但是,如果您的原始 JSON 数据没有任何问题,这应该不是问题。

【讨论】:

Bergi,他的缓存使用指针。不是数据的第二个副本。 @EdBayiates:我不是在谈论节点的副本吗?

以上是关于使用 GUID 作为键缓存“深度”JSON 对象的主要内容,如果未能解决你的问题,请参考以下文章

尝试使用 C# 中的 Guid 作为 Cassandra 中的主键

聊聊用 UUID/GUID 作为主键那些坑

如何使 EF-Core 使用 Guid 而不是 String 作为其 ID/主键

通过 NHibernate 代码映射将 GUID 属性作为外键映射到其他实体

使用唯一键展平/规范化深度嵌套的对象

Redis的应用场景