[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: What's wrong with this Lua code?
- From: William Ahern <william@...>
- Date: Fri, 16 Jun 2017 14:06:34 -0700
On Fri, Jun 16, 2017 at 08:18:10PM +0000, Jonathan Goble wrote:
<snip>
> Let's break it down:
>
> > local string = ""
>
> The variable `string` is now an empty string and, in this scope, no longer
> references the `string` standard library.
>
> > print(string.format("%X", 16777216))
>
> Here, Lua first looks up `string.format`. While `string` no longer refers
> to the string standard library, it is an actual string, and strings (since
> Lua 5.1) have a metatable with an __index metamethod pointing to the actual
> string library (which isn't changed by your local `string` assignment, nor
> would an assignment to the global `string` affect it). So the lookup of
> `string.format` produces, via metamethod, the string standard library
> function `format`. From there, you can call it with whatever arguments you
> want.
>
> So why is it a bad idea? One, because indexing through a metamethod is
> slower than directly indexing the actual `string` table, and two, because
> shadowing a built-in global (whether with a global or local assignment) is
> usually a code smell (in any language) and generally shouldn't be done
> without a very good reason.
OTOH, using the string global is actually more like _G.string.find,
requiring two VM index operations. Whereas an index through a local (or
immediate) value is a single VM index operation; the loading and indexing of
the metatable is direcly implemented as compiled C code that doesn't require
stepping through the VM interpreter and so theoretically should be much
faster.
... and my hypothesis checks out:
$ /tmp/bench.lua
256 subject:find 0.0001s
256 string.find 0.0001s
4096 subject:find 0.0010s
4096 string.find 0.0013s
65536 subject:find 0.0109s
65536 string.find 0.0114s
1048576 subject:find 0.1455s
1048576 string.find 0.1827s
16777216 subject:find 2.2815s
16777216 string.find 2.8463s
268435456 subject:find 36.6191s
268435456 string.find 45.4249s
Code:
local unix = require"unix"
local CLOCK_MONOTONIC = unix.CLOCK_MONOTONIC
local clock_gettime = unix.clock_gettime
for e=8,28,4 do
local n = math.pow(2, e)
do
local start = clock_gettime(CLOCK_MONOTONIC)
local subject = "foo"
for i=1,n do
subject:find("foo")
end
local elapsed = clock_gettime(CLOCK_MONOTONIC) - start
print(string.format("%-8d", n), "subject:find", string.format("%.4fs", elapsed))
end
do
local start = clock_gettime(CLOCK_MONOTONIC)
local subject = "foo"
for i=1,n do
string.find(subject, "foo")
end
local elapsed = clock_gettime(CLOCK_MONOTONIC) - start
print(string.format("%-8d", n), "string.find", string.format("%.4fs", elapsed))
end
end