【问题标题】:Large mutable byte array in ErlangErlang中的大型可变字节数组
【发布时间】:2025-12-18 09:20:07
【问题描述】:

当我在 Erlang 中编写一个简单的 Minecraft 服务器应用程序时,我现在关心如何有效地存储和修改块数据的问题。 对于那些不了解 Minecraft 内部结构的人:我需要在内存中存储大量大小高达 32kB 的二进制文件(100-1000)。到目前为止,Erlang 的内置二进制文件就足够了。但是服务器必须经常读取和更改这些二进制文件中的一些字节(通过它们的 id),我不想一直复制它们。
一个不错的功能是从/向 Erlang 的标准二进制文件导入和导出。

是否有任何 Erlang 扩展或数据库或我可以使用的任何东西?

【问题讨论】:

  • 最后,使用每个 4kB 大小的二进制文件解决了问题,并针对每个块更改进行编辑。虽然这不是更新效率的硬道理,但它节省了内存。如果您想查看,代码可在Github 获得。

标签: arrays memory erlang byte minecraft


【解决方案1】:

我的建议是使用“绳索”结构。基本上是一个树状结构,通常是一个张开或手指树,您只允许在其中更改树的某些部分。以正确的方式执行此操作可以让您两全其美:不变性和快速更新。

我不知道绳索实现,但这就是你想要做的。

另一种方法是将 ets 用作可变数组。这种东西速度很快。

第三种选择是使用空间树结构来表示您的世界。八叉树或类似 BSP 的结构是我盲目追求的东西。

【讨论】:

    【解决方案2】:

    由于二进制文件是只读的,我可以考虑以下方法(假设您预计更改率很高):

    1. 在叶子中使用具有相对较小的不可变二进制文件的树状结构。在这种情况下,当您修改数据时,您只需要重新创建小叶子二进制文件 + 直到根节点的所有节点。假设更改对于某个位置是“本地的”,我认为,您可以从 octo-tree 开始。
    2. 使用“大”二进制文件 + 更改列表(可以是简单的函数列表)。当您需要修改世界时,只需将新功能添加到列表中即可。当有人询问世界状态时,获取基本二进制文件并应用列表中的所有更改。不时地“压缩”所有更改并准备新的基线状态二进制文件。这可以与以前的方法(在叶子中具有成对的二进制/变化的树)结合使用。
    3. 将可变世界管理移至外部代码。您可以使用NIFsPorts。我想,这将是最快的方式。另外,我认为实现它会相对容易。 API的第一个版本可以像world:new(X, Y, Z) -> ref(); world:get(Ref, X, Y, Z); world:set(Ref, X, Y, Z, Value);一样简单

    【讨论】:

    • 感谢您的精彩回答!我想我会使用第二种方式,因为更改不是那么频繁(每秒不超过 5 个字节和播放器)。
    【解决方案3】:

    1000 个 32kb 的二进制文件没什么大不了的。你说改变一些字节?如果您只记录二进制文件可以包含或经常修改的不同部分,也许会更好,这样您就可以修改二进制文件的某些部分而无需复制其他部分。使用 ets,您不必担心一堆等待 gc'ed 的二进制副本。它仍然会制作副本,并且仍然是 gc'ed,但与进程的方式不同。您还可以使用 fullsweep_after 选项更频繁地进行进程清理。

    【讨论】: