如何在Elixir中获取变量的内存位置?

6
我们知道的一个关于Elixir的事实是,存储在内存中的数据结构是不可变的,而变量只是指向这些数据结构的指针
有没有一种方法可以获取变量指向的内存地址,而不是该内存位置中的内容(即变量的解引用值)?
对我而言,这样做的目的是为了学习Elixir/Erlang在处理重复值时如何管理内存,比如两个相同的字符列表,或者特别是在某些情况下元组和列表可能共享它们的内容,并编写更有效率的代码。
例如,当你更新一个元组时,除了被替换的条目外,所有条目都在旧元组和新元组之间共享。换句话说,在Elixir中,元组和列表能够共享它们的内容。
1个回答

16

TL;DR:

不,你无法获取变量的内存位置。

Discussion

原则上,一切都是复制的。每个进程都有自己的堆,事情就是这样的。

实际上有一些底层的速度优化。最明显的是:

  • 在编译时已知的文字从全局堆中引用(在某些情况下会带来巨大的性能提升)。
  • 大于 64 字节的二进制文件从全局堆中引用(这也导致二进制文件成为一个泄漏的抽象,因此需要使用binary:copy/1,2)。
  • 对大多数结构的更新实际上并不需要复制整个结构(尤其是关于Maps 内部发生了什么的问题)--但是需要复制多少和何时复制的情况随着更多的效率工作进入运行时而不断变化。
  • 垃圾回收发生在 每个进程 中,这就是为什么 Erlang 看起来具有神奇的增量 GC 方案,但实际上在通用情况下却具有相当无聊的代堆收集(即该方法是混合的 -- 是 EVM 性能增强不断发展的一部分...)。

如果你要为 EVM 编写代码,无论使用何种语言,你应该放弃尝试超越运行时的想法。这是因为试图在大多数 C(尤其是 C++)编译器优化中超越它们是几乎不被允许的做法。

每个主要版本都包含 一些 新实现的性能提升,不会违反语言的假设。如果你开始编写针对 R20 上某个特定底层内存方案“更有效”的代码,今天可能会获得一些微小的性能提升,但是当 R21 推出时,你的所有代码都很有可能被破坏,而你只能永远停留在 R20 上。

只需考虑一下R20.0 发布公告。跟上这类变化的步伐会消耗大部分开发时间。

有些项目的目的就是尝试反向黑客运行时。例如考虑Twisted。这些项目的存在特别在于,所有这些(大规模且非琐碎的)努力都不必在下游中的每个项目中重复。考虑到这一点,Erlang运行时、Core编译器、LFE项目和Elixir项目等本身就是进行此类速度优化的地方,而绝对不应该出现在下游客户端代码中。值得注意的是(是的!我的严格故事确实有个美好结局!),我们确实看到这种情况正在发生。
关于“效率”的说明:你追求什么样的效率?循环次数?总线通信?缓存未命中?财务成本?I/O操作的消除/旁路/写穿?更一般的选择性缓冲区处理?等等。
除非你要为已知硬件上的超紧密游戏引擎编写前端,并需要在今年实现高效(因为明年硬件将超越大多数速度优化),否则花费更多的CPU时间比开发人员必须花费的时间来解决针对具有数千个进程发送数百万短暂消息的高度并发运行时中发生的情况要便宜得多。
我最常见到的人们可能想“知道发生了什么”的情况是,他们试图将Elixir用作“更快的Ruby”,并编写了一个在EVM上的大型单线程程序而不是高度并发的系统。这种方法完全错过了在Erlang运行时上编写“快速”程序的重点。
如果您有一个非常特定的需要绝对需要快速调用的CPU密集任务,则可以选择:
- 用Rust或C编写的端口 - 用Rust或C编写的NIF - 可以与主节点进行网络通信的高性能计算节点,使用某个完美适合计算密集型任务的语言(BERT 对此非常有帮助) - 等待一两年,直到运行时采用更多的性能增强和硬件变得更快 - 对于并发系统,这种形式的速度增加率是完全疯狂的,特别是如果您在自己的硬件上运行(如果您在“云”中运行,当然,这些改进将受益于提供者而不是您,甚至在那种情况下,让自己为更多实例付费比试图瞒过运行时要便宜得多)。编写单独的程序(或 NIFs)使得特定问题的开发人员或团队能够在单一、统一、统一的问题空间中工作,只关注实现主项目分配给他们的任何协议合同。这比让 Erlang 或 LFE 或 Elixir 开发者/团队在编写一些 Erlang 代码之后再切换到编写一些 LangX 代码,然后再回到编写一些 Erlang 代码来说,明显更加高效,因为这样做需要进行上下文切换(或更糟糕的是,在熟练掌握一种语言的情况下,切换到一种自己不熟悉和缺乏经验的语言)。请注意,NIF 应被视为最后的选择,并且仅在您了解实际情况时才考虑使用。具体来说,您需要考虑以下情况:处理作业每次调用较小、可预测且范围良好,并且频繁的调用开销是您的瓶颈,而不是 NIF 内部处理速度。NIF 会破坏运行时的所有安全保证。崩溃的 NIF 就是崩溃的运行时 - 这正是 Erlang 设计时要避免的问题。任何人如果感觉足够自信可以随意推荐 C NIFs,显然缺乏足够的 C 经验来编写这些 NIFs。在项目层面上,效率问题主要是业务决策而不是技术决策。试图超越运行时是一个糟糕的商业(或社区管理,在社区 FOSS 的情况下)决策。

4
这个答案非常出色,令人难以置信地棒。 - Aleksei Matiushkin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接