Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are local variables accessed faster than global variables in lua?

So I was reading Programing in Lua 2nd Ed and I came across this paragraph here:

It is good programming style to use local variables whenever possible. Local variables help you avoid cluttering the global environment with unnecessary names. Moreover, the access to local variables is faster than to global ones.

Could anyone explain why this is? And is this "feature" only in Lua, or is it in other languages aswell? (e.g. C, C++, Java)

like image 952
Jdc1197 Avatar asked Feb 03 '12 16:02

Jdc1197


1 Answers

The difference in running time is due to the difference between hash table lookup and array lookup. An interpreter might be able to place a local variable in a CPU register, but even without such cleverness local variables are faster to access.

Global variables in Lua are stored in tables. Generally, anyone can modify these tables, and therefore the interpreter has to lookup a value anew every time it is being accessed. Local variables on the other hand disappear only when they go out of scope. Therefore they can have fixed locations in an array.

The benchmark program below calls a dummy function in a loop. The benchmark shows how the running time goes up the more tables the program has to jump through.

Other dynamic languages should be expected to have similar characteristics; see for example the Python benchmark at the very end.

Some relevant links:

  • Optimising Using Local Variables (Lua)
  • Local Variables (Python performance tips)
  • Optimizing Global Variable/Attribute Access. A (withdrawn) Python proposal on the lookup of global vs. local objects.

File demo.lua:

local M = {}
_G.demo = M
function M.op(x) return x end
return M

File main.lua:

local M = require "demo"

op = demo.op

local outer_op = demo.op

function iter_op(n)
    local inner_op = demo.op
    for i = 1, n do
        -- Example running times for n = 100,000,000 (Lua 5.2.0):

        -- Lookup a table (demo or _G), then lookup 'op'
        -- within that table:
        --
        -- demo.op(i)      --> 0:40
        -- _G.op(i)        --> 0:39

        -- Lookup 'op' within a known local table (M or the table of
        -- globals):
        --
        -- M.op(i)         --> 0:30
        -- op(i)           --> 0:30

        -- Dereference a local variable declared inside or outside
        -- of this iter_op() function:
        --
        -- inner_op(i)     --> 0:23
        -- outer_op(i)     --> 0:22
    end
end

iter_op(100000000)

File main.py:

import demo # Contains 'def op(x): return x'.

global_op = demo.op

def iter_op(n):
    local_op = demo.op
    for i in xrange(n):
        # Example running times for n = 50,000,000 (Python 2.6.5):
        # demo.op(i)     # 0:50
        # global_op(i)   # 0:41
        local_op(i)      # 0:36

iter_op(50000000)
like image 162
antonakos Avatar answered Jan 10 '23 15:01

antonakos