EventMachine

Event::Machine is an event-driven I/O and lightweight concurrency library for Ruby. It provides event-driven I/O using the Reactor pattern.

The reactor is the core of Event::Machine. All of EM's processing happens in the reactor. Your application will create code that hooks into the reactor, using timers, socket connections or various other means. Typically you'll wrap your entire application inside an EM#run block.

EventMachine.run do
  EventMachine.start_server ...
end

This block won't complete until EM#stop is called. The reactor will loop infinitely.

run y stop_event_loop

[~/ruby/eventmachine/simple(master)]$ cat timer.rb 
require 'rubygems'
require 'eventmachine'
puts "Start"
EM.run do
 puts "Init"
 EM.add_timer(1) do
   puts "Quitting"
   EM.stop_event_loop
 end
end
puts "Done"

[~/ruby/eventmachine/simple(master)]$ ruby timer.rb 
Start
Init
Quitting
Done

reactor_running?

[~/ruby/eventmachine/simple(master)]$ cat reactor_running.rb 
require 'rubygems'
require 'eventmachine'
puts EM.reactor_running?  # false
EM.run do
 puts EM.reactor_running? # true
 EM.next_tick do
   puts EM.reactor_running? # true
   EM.stop
 end
end
puts EM.reactor_running?  # false

  1. reactor_running? Tells you whether the EventMachine reactor loop is currently running.

    Useful when writing libraries that want to run event-driven code, but may be running in programs that are already event-driven.

    In such cases, if reactor_running? returns false, your code can invoke run and run your application code inside the block passed to that method. If this method returns true, just execute your event-aware code.

  2. (Object) next_tick(pr = nil, &block)

    Schedules a proc for execution immediately after the next "turn" through the reactor core.

add_timer

[~/ruby/eventmachine/simple(master)]$ cat add_timer_family.rb 
require "eventmachine"
EM.run do
 EM.add_periodic_timer(1) do
   puts "Tick..."
 end
 EM.add_timer(5) do
   puts "BOOM"
   EM.stop_event_loop
 end
end
[~/ruby/eventmachine/simple(master)]$ ruby add_timer_family.rb 
Tick...
Tick...
Tick...
Tick...
BOOM

  1. (Object) add_timer(*args, &block)

    Adds a one-shot timer to the event loop. Call it with one or two parameters. The first parameters is a delay-time expressed in seconds (not milliseconds). The second parameter, if present, must be an object that responds to :call. If 2nd parameter is not given, then you can also simply pass a block to the method call.

    This method may be called from the block passed to run or from any callback method. It schedules execution of the proc or block passed to it, after the passage of an interval of time equal to at least the number of seconds specified in the first parameter to the call.

    add_timer is a non-blocking method. Callbacks can and will be called during the interval of time that the timer is in effect. There is no built-in limit to the number of timers that can be outstanding at any given time.

  2. (Object) add_periodic_timer(*args, &block)

    Adds a periodic timer to the event loop. It takes the same parameters as the one-shot timer method, add_timer. This method schedules execution of the given block repeatedly, at intervals of time at least as great as the number of seconds given in the first parameter to the call.

next_tick

[~/ruby/eventmachine/simple(master)]$ cat next_tick.rb 
require 'eventmachine'
EM.run do
 EM.add_periodic_timer(1) do
   puts "Hai"
 end
 EM.add_timer(5) do
   EM.next_tick do
     EM.stop_event_loop
   end
 end
end
(Object) next_tick(pr = nil, &block) Schedules a proc for execution immediately after the next "turn" through the reactor core.

This can be useful for improving memory management and/or application responsiveness, especially when scheduling large amounts of data for writing to a network connection.

This method takes either a single argument (which must be a callable object) or a block.

Parameters:

pr (#call) (defaults to: nil) — A callable object to run

[~/ruby/eventmachine/simple(master)]$ ruby next_tick.rb 
Hai
Hai
Hai
Hai

defer

EM.defer is used to push a otherwise blocking operation on an EM internal queue whose jobs are then processed by a thread pool of 20 threads (by default).

You can use EM.defer with operations which aren’t made to work asynchronously.

[~/ruby/eventmachine/simple(master)]$ cat defer.rb 
require 'eventmachine'
require 'thread'
EM.run do
 EM.add_timer(2) do
   puts "Main #{Thread.current}"
   EM.stop_event_loop
 end
 EM.defer(proc do
   puts "Defer #{Thread.current}"
 end)
end
(Object) defer(op = nil, callback = nil, &blk)

  1. Event::Machine.defer is used for integrating blocking operations into Event::Machine's control flow.

  2. The action of defer is to take the block specified in the first parameter (the "operation") and schedule it for asynchronous execution on an internal thread pool maintained by Event::Machine.

  3. When the operation completes, it will pass the result computed by the block (if any) back to the Event::Machine reactor.

  4. Then, Event::Machine calls the block specified in the second parameter to defer (the "callback"), as part of its normal event handling loop.

  5. The result computed by the operation block is passed as a parameter to the callback.

  6. You may omit the callback parameter if you don't need to execute any code after the operation completes.

[~/ruby/eventmachine/simple(master)]$ ruby defer.rb 
Defer #<Thread:0x007fd9c3826960>
Main #<Thread:0x007fd9c38bcd98>

next_tick versus defer

  1. The loop runs on a single thread.
  2. What this means is that apart from I/O - at any time, only one task/event is processed by the event loop.
  3. You can imagine this event loop to be a queue of callbacks that are processed on every tick of the event loop.
  4. So, even if you are running on a multi-core machine, you will not get any parallelism in terms of actual processing - all events will be processed only one at a time.
  5. For every I/O bound task, you can simply define a callback that will get added to the event queue.
  6. The callback will fire when the I/O operation is done, and in the mean time, the application can continue to process other I/O bound requests.
  7. Given this model, what process.nextTick() actually does is defer the execution of an action till the next pass around the event loop.



Subsecciones
Casiano Rodriguez León 2015-06-18