如果您使用解释器,任何 Python 变量不太可能存在于不同表达式之间的寄存器中。您可以查看 Python 源代码如何编译为字节码。
Python 字节码(存储在解释器外部文件中的类型)是基于堆栈的(http://security.coverity.com/blog/2014/Nov/understanding-python-bytecode.html http://security.coverity.com/blog/2014/Nov/understanding-python-bytecode.html)。然后,该字节码被解释或 JIT 编译为本机机器代码。常规 python 仅进行解释,因此将 python 变量跨多个语句保存在机器寄存器中是不合理的.
用 C 编写的解释器可能会将字节码堆栈的顶部保留在解释循环内的局部变量中,而 C 编译器可能会将该 C 变量保留在寄存器中。因此,重复使用相同的 Python 变量可能最终不会有太多的存储/重新加载往返。
请注意,Broadwell CPU 上的存储转发延迟约为 4 或 5 个时钟周期,远低于 DRAM 往返的数百个周期。存储/重新加载甚至不必等待存储退出并提交到 L1D 缓存;它直接从存储缓冲区转发。有关的:http://blog.stuffedcow.net/2014/01/x86-memory-disambiguation/ http://blog.stuffedcow.net/2014/01/x86-memory-disambiguation/ and http://agner.org/optimize/ http://agner.org/optimize/,以及其他链接x86 /questions/tagged/x86标签维基)。对于 L1D 缓存命中,加载使用延迟也只有 5 个时钟周期(从地址准备好到数据准备好的延迟。您可以通过链表(在 asm 中)进行指针追踪来测量它。)有足够的解释器开销(总计它运行以确定下一步要做什么的指令数量),这甚至可能不是瓶颈。
对于解释器来说,将特定的 python 变量保存在寄存器中根本不合理。即使你用 asm 写了一个解释器,根本问题是寄存器不可寻址。 x86add r14d, eax
指令必须将两个寄存器硬编码到指令的机器代码中。 (所有其他 ISA 的工作方式都相同:寄存器号是指令机器代码的一部分,没有基于任何数据的间接寻址)。即使解释器做了工作来弄清楚它需要“将 reg-var #3 添加到 reg-var #2”(即将字节码堆栈操作解码回寄存器变量以获得它解释的内部表示),它也会必须使用与任何其他寄存器组合不同的功能。
给定一个整数,获取第 N 个寄存器的值的唯一方法是分支到使用该寄存器的指令,或者将所有寄存器存储到内存并索引结果数组。 (或者可能是某种无分支比较和掩码的东西)。
无论如何,尝试对此做任何具体的事情都是无利可图的,这就是为什么人们只用 C 编写解释器并让 C 编译器(希望)很好地优化实际运行的机器代码。
或者您编写一个 JIT 编译器,就像 Sun 为 Java 所做的那样(HotSpot VM)。 IDK 如果有 Python 的话。看Python 3 解释器有 JIT 功能吗? https://stackoverflow.com/questions/13034991/does-the-python-3-interpreter-have-a-jit-feature.
JIT 编译器实际上会将 Python 代码转换为机器代码,其中寄存器状态主要保存 Python 变量而不是解释器数据。同样,如果没有 JIT 编译器(或提前编译器),“将变量保存在寄存器中”就不是一回事。
它可能更快,因为它避免了 [] 运算符和其他开销(参见布伦的回答,您接受了)
脚注:一些 ISA 具有内存映射寄存器。例如AVR(8 位 RISC 微控制器),该芯片还具有内置 SRAM,其中包含低范围内存地址(包括寄存器)。因此,您可以执行索引加载并获取寄存器内容,但您也可能在未保存架构寄存器内容的内存上执行此操作。