为什么这个Lua优化技巧会提高性能? [英] Why would this Lua optimization hack improve performance?

查看:390
本文介绍了为什么这个Lua优化技巧会提高性能?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在查看文档,该文档描述了各种可提高Lua性能的技术脚本代码,令我震惊的是将需要此类技巧. (尽管我引用了Lua,但我在Javascript中也见过类似的黑客攻击.)

I'm looking over a document that describes various techniques to improve performance of Lua script code, and I'm shocked that such tricks would be required. (Although I'm quoting Lua, I've seen similar hacks in Javascript).

为什么需要这种优化:

例如,代码

For instance, the code

for i = 1, 1000000 do 
   local x = math.sin(i) 
end

运行速度比此速度慢30%:

runs 30% slower than this one:

local sin = math.sin 
for i = 1, 1000000 do
    local x = sin(i) 
end

他们正在本地重新声明sin函数.

They're re-declaring sin function locally.

为什么这会有所帮助?无论如何,这是编译器的工作.为什么程序员必须要做编译器的工作?

Why would this be helpful? It's the job of the compiler to do that anyway. Why is the programmer having to do the compiler's job?

我在Javascript中看到过类似的事情;因此很明显,解释编译器没有完成工作的原因很明显,这是 非常 的原因.什么事?

I've seen similar things in Javascript; and so obviously there must be a very good reason why the interpreting compiler isn't doing its job. What is it?

我在自己喜欢的Lua环境中反复看到它;人们将变量重新声明为本地变量:

I see it repeatedly in the Lua environment I'm fiddling in; people redeclaring variables as local:

local strfind = strfind
local strlen = strlen
local gsub = gsub
local pairs = pairs
local ipairs = ipairs
local type = type
local tinsert = tinsert
local tremove = tremove
local unpack = unpack
local max = max
local min = min
local floor = floor
local ceil = ceil
local loadstring = loadstring
local tostring = tostring
local setmetatable = setmetatable
local getmetatable = getmetatable
local format = format
local sin = math.sin

人们必须做编译器的工作是怎么回事?编译器是否对如何找到format感到困惑?为什么这是程序员必须处理的问题?为什么在1993年没有解决这个问题?

What is going on here that people have to do the work of the compiler? Is the compiler confused by how to find format? Why is this an issue that a programmer has to deal with? Why would this not have been taken care of in 1993?

我似乎也遇到了逻辑上的悖论:

I also seem to have hit a logical paradox:

  1. 不进行概要分析就不应进行优化
  2. 卢阿(Lua)无法简介
  3. 不应该优化Lua

推荐答案

为什么这会有所帮助?无论如何,这是编译器的工作.为什么程序员必须要做编译器的工作?

Why would this be helpful? It's the job of the compiler to do that anyway. Why is the programmer having to do the compiler's job?

语言是一种动态语言.编译器可以使用静态语言进行大量推理,例如将常量表达式退出循环.在动态语言中,情况有所不同.

Lua is a dynamic language. Compilers can do a lot of reasoning in static languages, like pulling constant expressions out of the loop. In dynamic languages, the situation is a bit different.

Lua的主要(也是唯一)数据结构是表. math也是一个表,即使它在这里用作名称空间.没有人能阻止您在循环中的某处修改math.sin函数(甚至认为这样做是不明智的),并且编译器在编译代码时也不知道这一点.因此,编译器完全按照您的指示执行操作:在循环的每次迭代中,在math表中查找sin函数并调用它.

Lua's main (and also only) data structure is the table. math is also just a table, even though it is used as a namespace here. Nobody can stop you from modifying the math.sin function somewhere in the loop (even thought that would be an unwise thing to do), and the compiler cannot know that when compiling the code. Therefore the compiler does exactly what you instruct it to do: in every iteration of the loop, lookup the sin function in the math table and call it.

现在,如果您知道不打算修改math.sin(即,您将要调用相同的函数),则可以将其保存在循环外的局部变量中.因为没有表查找,所以生成的代码更快.

Now, if YOU know that you are not going to modify math.sin (i.e. you are going to call the same function), you can save it in a local variable outside the loop. Because there are no table lookups, the resulting code is faster.

LuaJIT的情况略有不同-它使用跟踪和一些高级魔术来查看您的代码在运行时正在做什么 ,因此它实际上可以通过将表达式移到外部来优化循环循环和其他优化,除了将其实际编译为机器代码之外,还使其变得疯狂起来.

The situation is a bit different with LuaJIT - it uses tracing and some advanced magic to see what your code is doing in runtime, so it can actually optimize the loop by moving the expression outside of the loop, and other optimizations, apart from actually compiling it to machine code, making it crazy fast.

关于将变量声明为局部变量"-在定义模块时,很多时候,您都希望使用原始函数.使用全局变量访问pairsmax或其他任何内容时,没有人可以保证您每次调用都将具有相同的功能.例如, stdlib 重新定义了许多全局函数.

Regarding the the 'redeclaring variables as local' - many times when defining a module, you want to work with the original function. When accessing pairs, max or anything using their global variables, nobody can assure you that it will be the same function every call. For example stdlib redefines a lot of global functions.

通过创建与全局名称相同的局部变量,您实际上将函数存储在局部变量中,并且因为局部变量(按词法定义,因此在当前作用域和任何嵌套作用域中都是可见的)要优先于全局变量,请确保始终调用相同的函数.如果以后有人修改全局,则不会影响您的模块.更不用说它也更快,因为在全局表(_G)中查找了全局变量.

By creating a local variable with the same name as the global, you essentially store the function into a local variable, and because local variables (which are lexically scoped, meaning they are visible in the current scope and any nested scopes too) take precedence before globals, you make sure to always call the same function. Should someone modify the global later, it will not affect your module. Not to mention it is also faster, because globals are looked up in a global table (_G).

更新:我只是阅读了 Lua性能提示 Lua的作者之一Roberto Ierusalimschy,它几乎解释了您需要了解的有关Lua,性能和优化的所有知识. IMO最重要的规则是:

Update: I just read Lua Performance Tips by Roberto Ierusalimschy, one of Lua authors, and it pretty much explains everything that you need to know about Lua, performance and optimization. IMO the most important rules are:

第1条规则:不要这样做.

第2条规则:暂时不要这样做. (仅适用于专家)

Rule #2: Don’t do it yet. (for experts only)

这篇关于为什么这个Lua优化技巧会提高性能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆