Luaのはまりどころ
マイクロスレッドの比較対象のひとつとしてlua5.1を使ってみたけど、Luaって最近の言語と比べて結構独特な部分が多いなと思いました。以下、はまったところ:
- Tableを配列風に使うときの開始インデックスは1であることを忘れる
- Tableの存在しないインデックスの値や未定義変数の値もnilが返る
- cls.method(self) と書くところを cls:method(self) と書いても、その間違いに気がつきにくい
- localを書き忘れる
coroutine用channel実装と、生産者消費者例
-- many-to-many channel Channel = {} function Channel:new() local obj = setmetatable({}, {__index = self}) obj:init() return obj end function Channel:init() self.paused_sender = setmetatable({}, {__index = table}) self.paused_receiver = setmetatable({}, {__index = table}) self.msg = nil end function Channel:send(msg) if self.msg ~= nil then -- pause sender when buffer queue filled up self.paused_sender:insert(coroutine.running()) coroutine.yield() end self.msg = msg if #self.paused_receiver > 0 then -- resume paused receiver local paused = self.paused_receiver:remove(1) -- lua index start with 1 coroutine.resume(paused) end end function Channel:recv() if self.msg == nil then -- pause receiver when buffer queue empty self.paused_receiver:insert(coroutine.running()) coroutine.yield() end local msg = self.msg self.msg = nil if #self.paused_sender > 0 then -- resume paused sender local paused = self.paused_sender:remove(1) coroutine.resume(paused) end return msg end -- examples prod = coroutine.wrap( function (ch) print("prod start") for i = 1, 10 do ch:send(i * 2) end ch:send(-1) print("prod end") end) cons = coroutine.wrap( function (ch) print("cons start") while true do local msg = ch:recv() if msg == -1 then break end print("rcv: " .. msg) end print("cons end") end) ch = Channel:new() prod(ch) cons(ch)
幾分冗長な実装です。yield/resumeではパラメータを受け渡し可能なので、工夫すればmsgは不要になるでしょう。queueも実質ひとつでよく、senderかreceiver化どちらかをため続けるようにすればいいはず。