9 ms·
Perhaps I'm being a bit dense, but it's hard to see how one could take an existing asynchronous API and adapt it to use co-routines, since the point where you'd
by allertonm 16y ago
Perhaps I'm being a bit dense, but it's hard to see how one could take an existing asynchronous API and adapt it to use co-routines, since the point where you'd ideally want to "yield" is behind the API - and it may not be desirable or even possible to change this (for example, changing a C-based driver to use Ruby-level co-routines would be a challenge.) OTOH it's fairly straightforward to store a continuation and resume it in a callback.
So while I think you're correct, pragmatically I suspect this approach has more chance of being implemented.
- jules 16y agoWhy is yielding to a coroutine from inside a callback a problem, but calling a continuation isn't?
- allertonm 16y agoYielding inside a callback isn't a problem. I was actually thinking of the other yield you would need, the equivalent of suspending the continuation - but I later realize that this is no harder than the continuation case. So I was just being dense, my apologies. And it appears that Ilya (the OP) has been looking at this approach using fibers too http://www.igvita.com/2010/03/22/untangling-evented-code-with-ruby-fibers/ http://www.igvita.com/2010/03/22/untangling-evented-code-wit... - and the comment thread on the OP suggests that this is in use at Postrank.
- jules 16y agoThe problem with continuations is that they can be called multiple times, so before invoking it you have to copy the call stack associated with it and execute on the copy. Coroutines don't require copying anywhere. Creating a coroutine can be done in a couple of instructions (allocate a new stack and set the top of the stack to the code of the coroutine), and yielding is also just a few instructions (mov a new stack pointer and return). Essentially if you view coroutines and continuations as data structures then continuations are a functional / non destructive version of coroutines, and like other functional data structures they are slower. I don't know how Ruby fibers are implemented but they seem to have coroutine semantics, so they are probably very efficient as well. Adapting a callback library to coroutines is very simple. You have a user coroutine that runs the user code, and you have a system coroutine that manages the resource that calls you back when it's ready (e.g. downloading a web page). When the user code requests something from the resource it yields to the system coroutine. When the system has the response ready the system yields to the user code again. This is nearly the same for continuations, the difference is that yielding involves copying the stack of the continuation that is yielded to.