- More efficient timer implementation
In this release timers are removed immediately once they are cancelled, this is done is a (semi) efficient manner, more importantly it removes the overhead of lingering cancelled timers. This change enables the implementation of connection timeouts efficiently. - The reactor loop is now fiber (not thread) re-entrant
The reactor now may be run inside a fiber and when that fiber yields another one can grab the reactor and call run on it and it will just continue where it left off. This feature enables the building of fibered servers with near zero overhead for fast non-blocking connections.Here's how a fibered server would be written normally
@socket = TCPServer.new(..,..)
@reactor = Reactor::Base.new
@reactor.attach(:read, @socket) do
conn = @socket.accept
Fiber.new do
# handle connection here
end.resume
end
@reactor.run
As you can see, we spawn a fiber for each connection which adds up when we have many of those since each fiber requires a 4KB stack
Now it can be done like that
@socket = TCPServer.new(..,..)
@reactor = Reactor::Base.new
@reactor.attach(:read, @socket) do
conn = @socket.accept
# handle connection here
end
loop do
Fiber.new do
@reactor.run
end
end
Now the whole reactor loop runs in a fiber, if the connection does not block then it will run as if there is no fiber overhead, only when a connection blocks the reactor loop will break, a new fiber will be created and it will run the reactor again. This virtually removes the fiber overheads for non-blocking connections - Reactor#next_tick is now thread safe
When trying to access the reactor from other threads you can now schedule events using next_tick which will make sure the event is put in place gracefuly even in the presence of multiple threads fighting for the reactor. That's it though, you cannot safely access any other reactor methods from multiple threads, and it is up to you to ensure that the block provided to next_tick wont try to access variables that are shared among threads in an unsafe manner (it will be run in the context of the reactor's thread).
That's beside a few bug fixes here and there.
Grab it from here