我正在向ws2812模块添加一些代码,以便能够拥有某种可重复使用的缓冲区,在那里我们可以存储led值。
当前版本已存在。
我有两个问题。
首先,我想要一些"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
。但这个电话太慢了:在我的ESP8266上,大约有50个。如果每次通话都完成(例如,对于我的300次buffer:set
),大约需要15毫秒!
有没有更好的方法来获取一些用户数据并检查其类型,或者我应该在结构的开头添加一些"金丝雀"来进行自己的检查(与50us相比,这几乎是"免费的"…)?
为了让它看起来不那么像黑客,你可以尝试使用
local set = buffer.set
这本质上是相同的代码,但没有getmetatable,因为metatable是通过__index
元方法隐式使用的。
在我们的项目中,我们自己实现了luaL_checkudata
。正如您类似地建议的那样,一种选择是使用一个包含该类型的包装器对象。由于假设所有用户数据都被包装在包装器中,我们可以使用它来获取和确认用户数据的类型。但并没有进行基准测试,而是使用了测试元表。
我想说测试元表比封装慢,因为luaL_checkudata
做了很多工作来获取和测试元表,并且通过封装,我们可以直接访问类型。然而,基准测试肯定会说明问题。