Yielding 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.
The 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.