4 ms·
all the time is strong. I find them useful when conjoining function A with produces a sequence of results and function B which consumes the sequence†. Without
by jws 13y ago
all the time is strong.
I find them useful when conjoining function A with produces a sequence of results and function B which consumes the sequence†. Without coroutines you either have to turn one of the functions inside out to use it as a callback or break into threads and pass data between them.
With coroutines you can leave the functions in a more readable form and keep your cache footprint small by consuming the result as soon as it is produced.
␄
† I don't mean that I call A or B for each element of the sequence. A and B may have internal state and fill produce or consume the whole sequence in a single call. They could be organized to have a create function, a context structure, a "do one" call, and a destroy function… but that is a lot of noise and a lot of places for someone to make a mistake using them. A coroutine is cleaner.
- gte910h 13y agoCan I have an example here?
- spc476 13y agoHere's a Lua-esque (since Lua supports coroutines) example. I want to run a simple TCP echo server, so the main code that handles a connection ideally would look like this: function echo(socket) local remote,data = socket:read() if remote == nil then -- no data socket:close() return end socket:write(remote,data) return echo(socket) -- Tail call, this is a goto end Normally, such code would need to be run in a separate process or thread but that's too much overhead. You can use an event-based method (say, with poll() or epoll()) but then the code becomes inverted (or involves callbacks---which in this case isn't too bad, but imagine trying to implement, say, SMTP). With coroutines, we can still use an event-based mainloop, but still keep the imperative style of the original function above. Our event loop would look something like: function mainloop() local events = select:events() for i = 1 , #events do local err,keepgoing = coroutine.resume(events[i].code,events[i].socket,events[i].remote) if not keepgoing then select:remove(events[i].socket) events[i].socket:close() end end return mainloop() end and we would need to change our function just a bit: function echo() local socket,remote = coroutine.yield(true) local data = socket:read() if data == nil then return false end socket:write(remote,data) return echo() end Oh, and don't forget the coroutine to accept new connections: function echoconnection() local socket = coroutine.yield(true) local connection,remote = socket:accept() select:insert(connection,{ read = true } ,{ code = echo,remote = remote }) return echoconnection() end You can, of course, rewrite it such that socket:read() does the call to coroutine.yield(), but here I wanted to make it more explicit (as well as a shorter example) to fully hide the implementation (this is based on a working implementation I have in about 224 lines of Lua, which also handles signals and hides the coroutine calls from the main functions---the first example in this post would run as-is in the fully-blown implementation).
- 616c 13y agoVery cool stuff. I wanted to start learning Lua. Is there any way to see your code?
- spc476 13y agoWell, it's finicky. You'll need to install several custom written Lua modules [1]. These have been tested under Linux and Solaris. You will definitely have to edit the Makefile to exclude building some of the modules like org.conman.tcc [2] because of dependency issues (TCC isn't for the faint of heart). If you are on another Unix system, you'll probably be able to get most of it built (at the least, you'll need org.conman.process, org.conman.net and org.conman.pollset). You will also need to install LPeg [3]. Once all those are installed, then you'll be able to run the code: http://pastebin.com/ZBq5gSbS http://pastebin.com/ZBq5gSbS Or you can just look at the code: http://pastebin.com/ZBq5gSbS http://pastebin.com/ZBq5gSbS The coroutine stuff is there, just well hidden. I will also link to a sample multiuser chat room (no security, very basic): http://pastebin.com/u6vSPc69 http://pastebin.com/u6vSPc69 [1] https://github.com/spc476/lua-conmanorg https://github.com/spc476/lua-conmanorg [2] It's a Lua interface to the TCC library, which is a C compiler-as-a-library. Not used in the same code I posted, but it is something I find immensely useful, but I would classify as "advanced." [3] http://www.inf.puc-rio.br/~roberto/lpeg/ http://www.inf.puc-rio.br/~roberto/lpeg/ This is the Lua Parsing Expression Grammar library. If you are familiar with compiler tools, think lex and yacc (or flex and bison).