【问题标题】:How to get the memory location of a variable in Elixir?如何获取 Elixir 中变量的内存位置?
【发布时间】:2018-04-02 15:37:05
【问题描述】:

我们知道 Elixir 的一个事实是 data structures that lives in memory are immutable, and variables are just pointers to those data structures

有没有办法让我们获取变量指向的内存地址,而不是该内存位置中的内容(即变量的取消引用值)?


对我来说,这样做的目的是我们可以了解 Elixir/Erlang 在处理重复值时如何管理内存,比如两个相同的字符列表,或者特别是在某些情况下tuples and lists may share their contents,并编写更高效的代码.

例如,当您更新元组时,所有条目都在旧元组和新元组之间共享,但已替换的条目除外。换句话说,Elixir 中的元组和列表能够共享它们的内容。

【问题讨论】:

    标签: erlang elixir


    【解决方案1】:

    TL;DR:

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

    讨论

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

    实际上有一些潜在的速度技巧。最值得注意的是

    • 在编译时已知的文字从全局堆中引用(在某些情况下,这会带来巨大的性能提升)。
    • 大于 64 字节的二进制文件从全局堆中引用(这也导致二进制文件是一个泄漏抽象,因此 binary:copy/1,2)。
    • 对大多数结构的更新实际上并不需要复制整个结构(特别感兴趣的是 what goes on inside maps)——但是随着运行时工作效率的提高,需要复制的数量和时间一直在变化。
    • 垃圾收集发生在每个进程,这就是为什么 Erlang 看起来有一个神奇的高级增量 GC 方案,但实际上在下面有相当无聊的分代堆收集(在一般情况下,即;方法是actually somewhat of a hybrid -- 不断发展的 EVM 性能增强领域的另一部分...)。

    如果您要为 EVM 编写代码,无论使用何种语言,您都应该放弃要超越运行时的想法。这与试图超越大多数 C(尤其是 C++)编译器优化在几乎所有地方都是被禁止的做法的原因完全相同。

    每个主要版本都包含一些新实现的性能增强,不会破坏语言的假设。如果您开始编写针对 R20 上的某些特定底层内存方案“更高效”的代码,您今天可能会在这里或那里获得一些微小的性能提升,但是当 R21 出现时,您的所有代码很有可能会被打破,你将永远被 R20 困住。

    只需考虑the R20.0 release announcement。跟上这种性质的变化会占用您大部分的开发时间。

    一些项目将尝试回溯运行时作为其全部目的。例如,考虑Twisted。这样的项目特别存在,因此所有这些(大而重要的)工作不必在其下游的每个项目中重复。考虑到这一点,Erlang 运行时、Core 编译器、LFE 项目、Elixir 项目等它们自己 是这种速度黑客的地方,绝对不在下游客户端代码中。这里要注意的一件快乐的事情(是的!我的严厉故事有一个美好的结局!)是这正是我们所看到的

    关于“效率”的说明

    你追求什么样的效率?循环?公交车流量?缓存未命中? 财务成本? I/O-ops 消除/绕过/直写?更一般的选择性缓冲区处理?等等

    除非您要为超紧凑的游戏引擎编写前端在已知硬件上需要高效今年(因为明年硬件将使大多数速度相形见绌hacks 无论如何),支付更多的 CPU 时间比开发人员在大规模并发运行时中找出发生的事情所需的时间要便宜很多在不同的时间进行自己的垃圾收集。

    有人可能想“知道发生了什么”,我最常见的情况是人们试图将 Elixir 用作“更快的 Ruby”并且编写的不是大规模并发系统,而是一个大规模的并发系统。 EVM 之上的单线程程序。这种在 Erlang 运行时编写“快速”程序的方法完全没有抓住重点。

    如果您有一个非常具体的 CPU 密集型任务,绝对需要超快的速度,则需要其中之一

    • 用 Rust 或 C 编写的端口
    • 用 Rust 或 C 编写的 NIF
    • 一个高性能计算节点,可以通过网络与您的主节点进行通信,用某种语言编写,非常适合您的计算繁重任务(BERT 在那里很有帮助)
    • 等待一两年,运行时才能采用更多的性能增强和硬件以获得更快的速度——这种形式的速度提升速度对于并发系统来说是完全疯狂的,尤其是如果你'在您自己的硬件上运行(当然,如果您在“云”中运行,这些改进有利于提供者,但对您没有好处,即便如此让自己在更多情况下被骗比试图智取运行时更便宜)

    编写单独的程序(或 NIF)允许任何开发人员或团队在处理特定问题时在单个、统一、统一的问题空间中工作,只关心履行主项目交给他们的任何协议合同。这显着比让 Erlang 或 LFE 或 Elixir 开发/团队在编写一些 Erlang,然后是一些 LangX,然后又是一些 Erlang,上下文切换作为理所当然的事情(或更糟糕的是,上下文在他们擅长的一种语言和他们缺乏经验和幼稚的一种语言之间切换)。

    (请记住,NIF 应被视为最后的手段,并且在您了解实际情况时才考虑。具体而言,您的处理工作每次调用都很小、可预测且有界限的,频繁调用开销是你的瓶颈,而不是 NIF 中的处理速度。NIF 破坏了运行时的每一个安全保证。崩溃的 NIF 就是崩溃的运行时——这正是 Erlang 旨在避免的问题。任何人谁在 C 语言中感到足够自在,可以轻率地推荐 C NIFs显然缺乏足够的 C 语言经验来编写这些 NIFs。)

    在项目级别,效率问题主要是业务决策,而不是技术决策。试图超越运行时是一个糟糕的业务(或社区管理,在社区 FOSS 的情况下)。

    【讨论】:

    • 这是一个非常棒的答案。
    猜你喜欢
    • 2020-11-08
    • 2021-08-08
    • 2016-06-14
    • 2015-11-09
    • 1970-01-01
    • 2018-04-26
    • 2011-07-06
    • 2015-01-14
    • 2018-11-22
    相关资源
    最近更新 更多