2

我正在向 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.2 毫秒):

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.3 毫秒,快 4 倍以上),但它更像是一个 hack。:/ 有没有更好的方法来“缓存”缓冲区:设置分辨率?

第二个问题,在我的 C 代码中,我使用:

ws2812_buffer * buffer = (ws2812_buffer*)luaL_checkudata(L, 1, "ws2812.buffer");

这会返回我的缓冲区 ptr 并检查它是否真的是ws2812.buffer. 但是这个电话很慢:在我的 ESP8266 上,~50us。如果每次通话都完成(buffer:set例如我的 300 次),它是 ~15 毫秒!

有没有更好的方法来获取一些用户数据并检查其类型,或者我应该在结构的开头添加一些“金丝雀”来进行自己的检查(与 50us 相比,这几乎是“免费的”......)?

4

1 回答 1

3

为了让它看起来不那么黑客,你可以尝试使用

local set = buffer.set

这本质上是相同的代码,但没有 getmetatable,因为 metatable 是通过__indexmetamethod 隐式使用的。

在我们的项目中,我们自己实现了luaL_checkudata. 一个选项 - 正如您同样建议的那样 - 是使用包含该类型的包装器对象。由于假设所有用户数据都被包装在包装器中,我们可以使用它来获取和确认用户数据的类型。但是没有进行基准测试,而是使用了测试元表。

我会说测试元表比包装要慢,因为luaL_checkudata需要做很多工作来获取和测试元表,并且通过包装我们可以直接访问类型。但是,基准测试可以确定。

于 2015-12-26T15:20:23.187 回答