Lua 的速度为什么比 Python 快?
Lua 和 Python 同为虚拟机解释型脚本语言,为什么 Lua 的执行速度比 Python 高?
回复内容:
前面几位已经说的很好,我来做一下补充。@冯东 和 @庞巍伟 都提到了Lua使用的是register-based的虚拟机设计,我看到下面有人评论说既然这种VM的设计性能高,那么为什么Python和java还是使用的stack-based的设计。
我的理解是实现难度吧,register-based的设计中,一个操作需要关注到指令的操作数到底存放在哪里,而stack-based的不需要,它分开了几条指令,首先加载数据到栈顶,然后再进行操作,操作时默认的认为数据就存在栈顶了。(如果不清楚这个过程,可以拖上去看看 @庞巍伟 的回答,就不在这里列出来了)
简单的说,register-based的指令格式设计把stack-based的指令中分几条指令要完成的事情用一条指令搞定了,快当然是快了,难度也加大了。
另外还有一点上面的回答中似乎没有提到,Lua使用的是一遍遍历就生产指令的方式,学过编译原理的,大概都能知道一般分两遍遍历,第一遍生成AST,再一遍遍历AST生成指令,而在Lua中是直接跳过了AST指令这一步的。
还是那句话,快是快了,代码的实现难度也大了些。最早的Lua解释器,也是使用lex、yacc这样的工具来自动生成代码的,后来为了提升性能,作者改成了自己手写的递归下降的分析器。这部分代码是我认为Lua代码中最难理解的一个部分了--因为它要一遍分析干太多的事情了。
我在阅读Lua代码的过程中,能充分感受到作者为了Lua在性能上的提升花费的心血,致敬。 有一些 PUC-Rio Lua(也就是没 JIT 的)和 Python 的 benchmark 对比。结论是 Python 比 C 大约慢 70 倍,Lua 大约慢 30-40 倍。
Lua 是 register-based VM。所谓的寄存器,其实并不神秘,就是 runtime stack 的 topmost frame [1] 是可以被 VM 指令随机访问的。至于为什么 CPU 里的某种硬件也叫寄存器,原因在这里有解释:《什么是寄存器》。
Stack frame 可以被随机访问之后,在同一个 VM 指令里就可以用 native code 一次做很多事情。
可以看云风的这篇 blog:《云风的 BLOG: 虚拟机之比较,lua 5 的实现》
- Stack frame 就是 stack 中属于同一个 function invocation 的所有 stack entries。
最关键的是, lua 是基于寄存器的虚拟机实现,而python还有很多其他脚本语言是基于堆栈的,基于寄存器的虚拟机字节码更简单,更高效,因为register based vm的字节码,一般同时包含了指令/操作数/操作目标等.
对比简单的加法操作:
stack based 生成的字节码大概是这样(仅仅是模拟,不代表实际)
PUSH 1
PUSH 2
ADD // ADD 的操作结果存放eax
PUSH eax // 将结果push入堆栈,以便后面的代码不会覆盖eax
而register based 生成的字节码大概是这样:
ADD 1,2,R1
就一行,R1存放1+2的结果
就这么简答的操作就已经相差4条指令,所以基于寄存器的虚拟机字节码运行更有效率. python的一些设计特性,例如完全面向对象,同时也是它在性能表现上的负担。
举个很简单的例子:
<span class="k">def</span> <span class="nf">test</span><span class="p">():</span> <span class="n">a</span> <span class="o">=</span> <span class="mi">1</span> <span class="n">b</span> <span class="o">=</span> <span class="mi">2</span> <span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span>
lua 最新的5.3 已经支持整数类型, 加上基于寄存器的VM和优秀的编译器, 想慢都难 抛个砖,引个玉。
1. 基于栈和基于寄存器的不同是主要的性能差异原因。这点大家也都解析的非常清楚了,也很好想象。基于栈的求值过程必须使用栈顶的值,想想也知道是反人类的(哦不,反机器的-_-!)。因此会出现很多的push(load)和pop(store)指令,而基于寄存器的指令就一条完事了。但这都是在解释执行的情况下,如果编译到本地指令之后,理论上来说,基于寄存器还是基于栈的实现并没有太多影响,因为都转换成了硬件寄存器,两者的转换过程的开销也没有太多差别。
2. 为什么采用基于栈的虚拟机,除了实现简单(后序遍历AST就有了)之外,占用空间小也是一个基于栈的虚拟机的特点,便于网络传输和嵌入式设备。Java在设计之初就是考虑到网络方面的应用,比如Applet技术,以及嵌入式设备的运用。
3. 个人还有一个想法,不知道是否靠谱@RednaxelaFX。基于栈的虚拟机的指令更加完整地保留了源代码的求值过程,几乎是AST直接『压平』的结果,甚至很容易逆回源代码。这就意味着基于栈的指令在后续操作中可以很容易转换成需要的形式,以便于在不同的形式上做优化。栈代码转换成寄存器代码没有什么效率影响,而寄存器代码转换成栈代码就会出现比遍历AST生成还要多的push(load)和pop(store)指令。栈代码的生成适合直接从AST后续遍历得到,因为求值的过程都是围绕着栈顶。简而言之,栈代码是一个可塑性比较强的代码,先存着,后面想怎么处理都保留了可能性。
4. 语法分析到代码生成过程减少pass数,个人觉得并没有太大的意义。严格来讲这个过程的效率应该不能算是performance的效率,最多只是加快了从源码的启动时间。Performance应该从解释执行开始比较。有的时候单趟编译造成了复杂性反而得不偿失,AST这样的数据结构就适合在上面干该干的事。
5. 实际中虚拟机的效率还和很多其他啊因素有关。比如很重要的方面就是垃圾回收。
6. 至于上升到指令集设计高度的话,不太了解,请R大来。 @RednaxelaFX。他应该会贴个这个传送门虚拟机随谈(一):解释器,树遍历解释器,基于栈与基于寄存器,大杂烩 Lua的指令集非常非常非常简单,我对着指令说明看了半个小时就能看懂lua的汇编代码了,再花十来分钟就能手动修改lua二进制代码了。而我甚至没完整看过lua的源码。 占坑 以我的观点,最大的关键是在 lua 在语言层面相比 python 简单了很多,所以他们的实现相应的就有了速度的差别。

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

熱門話題

PHP和Python各有優劣,選擇取決於項目需求和個人偏好。 1.PHP適合快速開發和維護大型Web應用。 2.Python在數據科學和機器學習領域佔據主導地位。

在CentOS系統上啟用PyTorchGPU加速,需要安裝CUDA、cuDNN以及PyTorch的GPU版本。以下步驟將引導您完成這一過程:CUDA和cuDNN安裝確定CUDA版本兼容性:使用nvidia-smi命令查看您的NVIDIA顯卡支持的CUDA版本。例如,您的MX450顯卡可能支持CUDA11.1或更高版本。下載並安裝CUDAToolkit:訪問NVIDIACUDAToolkit官網,根據您顯卡支持的最高CUDA版本下載並安裝相應的版本。安裝cuDNN庫:前

Python和JavaScript在社區、庫和資源方面的對比各有優劣。 1)Python社區友好,適合初學者,但前端開發資源不如JavaScript豐富。 2)Python在數據科學和機器學習庫方面強大,JavaScript則在前端開發庫和框架上更勝一籌。 3)兩者的學習資源都豐富,但Python適合從官方文檔開始,JavaScript則以MDNWebDocs為佳。選擇應基於項目需求和個人興趣。

Docker利用Linux內核特性,提供高效、隔離的應用運行環境。其工作原理如下:1. 鏡像作為只讀模板,包含運行應用所需的一切;2. 聯合文件系統(UnionFS)層疊多個文件系統,只存儲差異部分,節省空間並加快速度;3. 守護進程管理鏡像和容器,客戶端用於交互;4. Namespaces和cgroups實現容器隔離和資源限制;5. 多種網絡模式支持容器互聯。理解這些核心概念,才能更好地利用Docker。

MinIO對象存儲:CentOS系統下的高性能部署MinIO是一款基於Go語言開發的高性能、分佈式對象存儲系統,與AmazonS3兼容。它支持多種客戶端語言,包括Java、Python、JavaScript和Go。本文將簡要介紹MinIO在CentOS系統上的安裝和兼容性。 CentOS版本兼容性MinIO已在多個CentOS版本上得到驗證,包括但不限於:CentOS7.9:提供完整的安裝指南,涵蓋集群配置、環境準備、配置文件設置、磁盤分區以及MinI

在CentOS系統上進行PyTorch分佈式訓練,需要按照以下步驟操作:PyTorch安裝:前提是CentOS系統已安裝Python和pip。根據您的CUDA版本,從PyTorch官網獲取合適的安裝命令。對於僅需CPU的訓練,可以使用以下命令:pipinstalltorchtorchvisiontorchaudio如需GPU支持,請確保已安裝對應版本的CUDA和cuDNN,並使用相應的PyTorch版本進行安裝。分佈式環境配置:分佈式訓練通常需要多台機器或單機多GPU。所

在CentOS系統上安裝PyTorch,需要仔細選擇合適的版本,並考慮以下幾個關鍵因素:一、系統環境兼容性:操作系統:建議使用CentOS7或更高版本。 CUDA與cuDNN:PyTorch版本與CUDA版本密切相關。例如,PyTorch1.9.0需要CUDA11.1,而PyTorch2.0.1則需要CUDA11.3。 cuDNN版本也必須與CUDA版本匹配。選擇PyTorch版本前,務必確認已安裝兼容的CUDA和cuDNN版本。 Python版本:PyTorch官方支

CentOS 安裝 Nginx 需要遵循以下步驟:安裝依賴包,如開發工具、pcre-devel 和 openssl-devel。下載 Nginx 源碼包,解壓後編譯安裝,並指定安裝路徑為 /usr/local/nginx。創建 Nginx 用戶和用戶組,並設置權限。修改配置文件 nginx.conf,配置監聽端口和域名/IP 地址。啟動 Nginx 服務。需要注意常見的錯誤,如依賴問題、端口衝突和配置文件錯誤。性能優化需要根據具體情況調整,如開啟緩存和調整 worker 進程數量。
