我正在向ws2812模块添加一些代码,以便能够存储某种可重用的缓冲区,我们可以存储led值。
当前版本为there。
我有两个问题。
首先,我想要一些“OO风格”的界面。所以我做了:
local buffer = ws2812.newBuffer(300);
for j = 0,299 do
buffer:set(j, 255, 255, 255)
end
buffer:write(pin);
这里的问题是buffer:set
在每次循环转换时被解析,这是昂贵的(这个循环需要大约20.2ms):
8 [2] FORPREP 1 6 ; to 15
9 [3] SELF 5 0 -7 ; "set"
10 [3] MOVE 7 4
11 [3] LOADK 8 -8 ; 255
12 [3] LOADK 9 -8 ; 255
13 [3] LOADK 10 -8 ; 255
14 [3] CALL 5 6 1
15 [2] FORLOOP 1 -7 ; to 9
我发现这个问题的解决方法看起来不太好看:
local buffer = ws2812.newBuffer(300);
local set = getmetatable(buffer).set;
for j = 0,299 do
set(buffer, j, 255, 255, 255)
end
buffer:write(pin);
它运行良好(循环4.3ms,快4倍以上),但它更像是黑客。 :/有没有更好的方法来“缓存”缓冲区:设置分辨率?
第二个问题,在我的C代码中,我使用:
ws2812_buffer * buffer = (ws2812_buffer*)luaL_checkudata(L, 1, "ws2812.buffer");
返回我的缓冲区ptr并检查它是否真的是ws2812.buffer
。但是这个叫做sloooooow:在我的ESP8266上,~50us。如果它在每次通话时完成(例如我的300次buffer:set
),那就是〜15ms!
有没有更好的方法来获取一些用户数据并检查其类型,或者我应该在我的结构的开头添加一些“金丝雀”来做我自己的检查(与50us相比几乎是“免费的”.. 。)?
答案 0 :(得分:3)
为了让它看起来不那么糟糕,你可以尝试使用
local set = buffer.set
这基本上是相同的代码,但没有getmetatable,因为metatable通过__index
metamethod隐式使用。
在我们的项目中,我们自己实现了luaL_checkudata
。
一个选项 - 正如您所建议的那样 - 是使用包含该类型的包装器对象。由于假定所有userdata都包装在包装器中,我们可以使用它来获取并确认userdata的类型。但是没有进行基准测试,而是使用了测试元数据。
我想说测试metatables比包装慢,因为luaL_checkudata
做了很多工作来测试metatables并且通过包装我们可以直接访问这个类型。然而,基准测试肯定会证明。