Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
EventMachine  EM.run{ awesome_stuff! }                             Christopher Spring
@autonomous
EventMachine
EventMachine
• Mostly IO bound• Handle thousands  concurrent connections• Stream data• Real time data delivery• You’ve got Mad Ruby Ski...
What is EventMachine?• Toolkit for creating evented applications• Implementation of the Reactor Pattern• MRI,YARV, jRuby, ...
Evented?
Evented?puts(1)puts(2)puts(3)
Evented?puts(1)puts(2)puts(3)             puts(1)             work{ puts(3) }             puts(2)
Reactor pattern“Event handling pattern for handling servicerequests delivered concurrently to a servicehandler by one or m...
Http   Keyboard     Udp   etc                   Service handler                    Demultiplexer                   Event d...
Http   Keyboard     Udp   etc                   Service handler                    Demultiplexer                   Event d...
Http   Keyboard     Udp   etc                   Service handler                    Demultiplexer                   Event d...
Benefits• Application code separate from reactor• Non blocking IO• Single process• No threads!
Limitations• Demultiplexing limits• Some others we’ll cover later...
Teh Basics• EM.run• EM.connection• EM.next_tick• EM.defer• EM::Queue• EM::Channel
Teh Basics• EM.run• EM.connection• EM.next_tick• EM.defer• EM::Queue• EM::Channel
require "rubygems"require "eventmachine"EM.run do  # ...  EM.stopend
... don’t do this!• big ass loops  •   1_000_000.times{}  •   while condition?• sleep• blocking IO
Teh Basics• EM.run• EM.connection• EM.next_tick• EM.defer• EM::Queue• EM::Channel
class EchoServer < EM::Connection  def post_init    puts "New connection"  end  def unbind    puts "Connection closed"  en...
class EchoServer < EM::Connection  def post_init    puts "New connection"  end  def unbind    puts "Connection closed"    ...
# TCPEM.run do  EM.start_server(127.0.0.1, 9000, EchoServer)end# UDPEM.run do  EM.open_datagram_socket(127.0.0.1, 9000, Ec...
class EchoClient < EM::Connection  def post_init    puts "Sending stuff to server"    send_data("Why, hello there!")  end ...
class EchoClient < EM::Connection  def post_init    puts "Sending stuff to server"    send_data("Why, hello there!")  end ...
Teh Basics• EM.run• EM.connection• EM.next_tick• EM.defer• EM::Queue• EM::Channel
EM.run do  EM.next_tick do    # ... awesome stuff  endend
Task 1Task 2Task 3
Task 1Task 2Task 3 EM.run{ }
Task 1Task 2Task 3 EM.run{ } EM.next_tick{ }
Teh Basics• EM.run• EM.connection• EM.next_tick• EM.defer• EM::Queue• EM::Channel
EM.run do  EM.defer do    send_email( user1 )  end  EM.defer do    send_email( user2 )  end  EM.defer do    send_email( us...
Email 1Email 2Email 3
Email 1Email 2Email 3 EM.defer{ }
EM.run do  get_stuff = Proc.new do    # ...    long_running_io()  end  use_stuff = Proc.new do |io_results|    # ...  end ...
Teh Basics• EM.run• EM.connection• next_tick; add_timer; add_periodic_timer• EM.defer• EM::Queue• EM::Channel
EM.run do  queue = EM::Queue.new  # ...  queue.push( data1, data2 )  # ...  queue.pop { |data| puts data } # >> data1end
EM.run do  queue = EM::Queue.new  EM.defer do    sleep( 2 )    queue.push( some@email.com )    sleep( 3 )    queue.push( s...
Teh Basics• EM.run• EM.connection• EM.next_tick• EM.defer• EM::Queue• EM::Channel
EM.run do  channel = EM::Channel.new  EM.defer do    channel.subscribe do |msg|      puts "Received #{msg}"    end  end  E...
Deferrable• Light weight concurrency• Delayed execution with triggers • :succeeded • :failed • nil• callback and errback
class LoanRequest  include EM::Deferrable  def initialize( name )    @name = name    callback do |who|      puts "Approved...
class LoanRequest  include EM::Deferrable  def initialize( name )    @name = name    callback do |who|              EM.run...
class LoanRequest  include EM::Deferrable  def initialize( name )    @name = name    callback do |who|              EM.run...
state: nil
state: nilcallback{}callback{}callback{}
state: nilcallback{}                errback{}callback{}                errback{}callback{}
state: succeededcallback{}                      errback{}callback{}                      errback{}callback{}
state: succeededcallback{}callback{}callback{}
state: succeeded
state: failedcallback{}                   errback{}callback{}                   errback{}callback{}
state: failed                errback{}                errback{}
state: failed
class Mailer  include EM::Deferrable  def add_mailing(val)    callback do      sleep 1      puts "Sent #{val}"    end  end...
EM.run do                                m = Mailer.newclass Mailer                                m.add_mailing(1)  inclu...
EM.run do                                m = Mailer.newclass Mailer                                m.add_mailing(1)  inclu...
Gotchas• Inverted flow of control can make  debugging difficult• Synchronous code will slow it down • Use/Write libraries fo...
Worth checking out• EM-Synchrony:  https://github.com/igrigorik/em-synchrony• Goliath:  https://github.com/postrank-labs/g...
Baie Dankie!
Questions?
EventMachine for RubyFuZa   2012
EventMachine for RubyFuZa   2012
EventMachine for RubyFuZa   2012
Upcoming SlideShare
Loading in …5
×

EventMachine for RubyFuZa 2012

3,878 views

Published on

lighting tour of eventmachines basic structures

Published in: Technology, Business
  • Login to see the comments

EventMachine for RubyFuZa 2012

  1. 1. EventMachine EM.run{ awesome_stuff! } Christopher Spring
  2. 2. @autonomous
  3. 3. EventMachine
  4. 4. EventMachine
  5. 5. • Mostly IO bound• Handle thousands concurrent connections• Stream data• Real time data delivery• You’ve got Mad Ruby Skills
  6. 6. What is EventMachine?• Toolkit for creating evented applications• Implementation of the Reactor Pattern• MRI,YARV, jRuby, Rubinius
  7. 7. Evented?
  8. 8. Evented?puts(1)puts(2)puts(3)
  9. 9. Evented?puts(1)puts(2)puts(3) puts(1) work{ puts(3) } puts(2)
  10. 10. Reactor pattern“Event handling pattern for handling servicerequests delivered concurrently to a servicehandler by one or more inputs. The servicehandler then demultiplexes the incomingrequests and dispatches them synchronouslyto the associated request handlers.” http://en.wikipedia.org/wiki/Reactor_pattern
  11. 11. Http Keyboard Udp etc Service handler Demultiplexer Event dispatcherEvent Handler AEvent Handler BEvent Handler CEvent Handler D
  12. 12. Http Keyboard Udp etc Service handler Demultiplexer Event dispatcherEvent Handler AEvent Handler BEvent Handler CEvent Handler D
  13. 13. Http Keyboard Udp etc Service handler Demultiplexer Event dispatcher Thread 1Event Handler A Thread 2Event Handler B ...Event Handler CEvent Handler D Thread 20
  14. 14. Benefits• Application code separate from reactor• Non blocking IO• Single process• No threads!
  15. 15. Limitations• Demultiplexing limits• Some others we’ll cover later...
  16. 16. Teh Basics• EM.run• EM.connection• EM.next_tick• EM.defer• EM::Queue• EM::Channel
  17. 17. Teh Basics• EM.run• EM.connection• EM.next_tick• EM.defer• EM::Queue• EM::Channel
  18. 18. require "rubygems"require "eventmachine"EM.run do # ... EM.stopend
  19. 19. ... don’t do this!• big ass loops • 1_000_000.times{} • while condition?• sleep• blocking IO
  20. 20. Teh Basics• EM.run• EM.connection• EM.next_tick• EM.defer• EM::Queue• EM::Channel
  21. 21. class EchoServer < EM::Connection def post_init puts "New connection" end def unbind puts "Connection closed" end def receive_data(data) send_data ">> #{data}" endendEM.run do EM.start_server(127.0.0.1, 9000, EchoServer) puts "Started server at 127.0.0.1:9000"end
  22. 22. class EchoServer < EM::Connection def post_init puts "New connection" end def unbind puts "Connection closed" # $ telnet localhost 9000 end # Hello # >> Hello def receive_data(data) # Bye send_data ">> #{data}" # >> Bye endendEM.run do EM.start_server(127.0.0.1, 9000, EchoServer) puts "Started server at 127.0.0.1:9000"end
  23. 23. # TCPEM.run do EM.start_server(127.0.0.1, 9000, EchoServer)end# UDPEM.run do EM.open_datagram_socket(127.0.0.1, 9000, EchoServer)end# Unix-domain serverEM.run do EM.start_unix_domain_server(/tmp/sock, nil, EchoServer)end
  24. 24. class EchoClient < EM::Connection def post_init puts "Sending stuff to server" send_data("Why, hello there!") end def unbind puts "Connection closed" end def receive_data(data) puts ">> #{data}" endendEM.run do EM.connect(127.0.0.1, 9000, EchoClient)end
  25. 25. class EchoClient < EM::Connection def post_init puts "Sending stuff to server" send_data("Why, hello there!") end def unbind puts "Connection closed" end def receive_data(data) puts ">> #{data}" endendEM.run do EM.connect(127.0.0.1, 9000, EchoClient)end
  26. 26. Teh Basics• EM.run• EM.connection• EM.next_tick• EM.defer• EM::Queue• EM::Channel
  27. 27. EM.run do EM.next_tick do # ... awesome stuff endend
  28. 28. Task 1Task 2Task 3
  29. 29. Task 1Task 2Task 3 EM.run{ }
  30. 30. Task 1Task 2Task 3 EM.run{ } EM.next_tick{ }
  31. 31. Teh Basics• EM.run• EM.connection• EM.next_tick• EM.defer• EM::Queue• EM::Channel
  32. 32. EM.run do EM.defer do send_email( user1 ) end EM.defer do send_email( user2 ) end EM.defer do send_email( user3 ) endend
  33. 33. Email 1Email 2Email 3
  34. 34. Email 1Email 2Email 3 EM.defer{ }
  35. 35. EM.run do get_stuff = Proc.new do # ... long_running_io() end use_stuff = Proc.new do |io_results| # ... end # ... EM.defer( get_stuff, use_stuff )end
  36. 36. Teh Basics• EM.run• EM.connection• next_tick; add_timer; add_periodic_timer• EM.defer• EM::Queue• EM::Channel
  37. 37. EM.run do queue = EM::Queue.new # ... queue.push( data1, data2 ) # ... queue.pop { |data| puts data } # >> data1end
  38. 38. EM.run do queue = EM::Queue.new EM.defer do sleep( 2 ) queue.push( some@email.com ) sleep( 3 ) queue.push( some@one.com) end welcomer = Proc.new do |email| send_welcome( email ) EM.next_tick( queue.pop(&welcomer) ) end queue.pop(&welcomer);end
  39. 39. Teh Basics• EM.run• EM.connection• EM.next_tick• EM.defer• EM::Queue• EM::Channel
  40. 40. EM.run do channel = EM::Channel.new EM.defer do channel.subscribe do |msg| puts "Received #{msg}" end end EM.add_periodic_timer(1) do channel << Time.now endend
  41. 41. Deferrable• Light weight concurrency• Delayed execution with triggers • :succeeded • :failed • nil• callback and errback
  42. 42. class LoanRequest include EM::Deferrable def initialize( name ) @name = name callback do |who| puts "Approved #{who}!" end errback do |who| puts "Denied #{who}!" end end def approved! # succeed( *args ) set_deferred_status(:succeeded, @name) end def denied! # fail( *args ) set_deferred_status(:failed, @name) endend
  43. 43. class LoanRequest include EM::Deferrable def initialize( name ) @name = name callback do |who| EM.run do puts "Approved #{who}!" s1 = LoanRequest.new(Marc) end s1.approved! errback do |who| s2 = LoanRequest.new(Chris) puts "Denied #{who}!" EM.add_timer(2){ s2.denied! } end end end def approved! # succeed( *args ) set_deferred_status(:succeeded, @name) end def denied! # fail( *args ) set_deferred_status(:failed, @name) endend
  44. 44. class LoanRequest include EM::Deferrable def initialize( name ) @name = name callback do |who| EM.run do puts "Approved #{who}!" s1 = LoanRequest.new(Marc) end s1.approved! errback do |who| s2 = LoanRequest.new(Chris) puts "Denied #{who}!" EM.add_timer(2){ s2.denied! } end end end def approved! # succeed( *args ) set_deferred_status(:succeeded, @name) end # :00 Approved Marc! # :02 Denied Chris! def denied! # fail( *args ) set_deferred_status(:failed, @name) endend
  45. 45. state: nil
  46. 46. state: nilcallback{}callback{}callback{}
  47. 47. state: nilcallback{} errback{}callback{} errback{}callback{}
  48. 48. state: succeededcallback{} errback{}callback{} errback{}callback{}
  49. 49. state: succeededcallback{}callback{}callback{}
  50. 50. state: succeeded
  51. 51. state: failedcallback{} errback{}callback{} errback{}callback{}
  52. 52. state: failed errback{} errback{}
  53. 53. state: failed
  54. 54. class Mailer include EM::Deferrable def add_mailing(val) callback do sleep 1 puts "Sent #{val}" end end def connection_open! puts Open connection succeed end def connection_lost! puts Lost connection set_deferred_status nil endend
  55. 55. EM.run do m = Mailer.newclass Mailer m.add_mailing(1) include EM::Deferrable m.add_mailing(2) m.connection_open! def add_mailing(val) callback do EM.add_timer(1) do sleep 1 m.connection_lost! puts "Sent #{val}" EM.add_timer(2) do end m.add_mailing(3) end m.add_mailing(4) m.connection_open! def connection_open! end puts Open connection end succeed end end def connection_lost! puts Lost connection set_deferred_status nil endend
  56. 56. EM.run do m = Mailer.newclass Mailer m.add_mailing(1) include EM::Deferrable m.add_mailing(2) m.connection_open! def add_mailing(val) callback do EM.add_timer(1) do sleep 1 m.connection_lost! puts "Sent #{val}" EM.add_timer(2) do end m.add_mailing(3) end m.add_mailing(4) m.connection_open! def connection_open! end puts Open connection end succeed end end def connection_lost! # Open connection puts Lost connection # Sent 1 set_deferred_status nil # Sent 2 end # Lost connectionend # Open connection # Sent 3 # Sent 4
  57. 57. Gotchas• Inverted flow of control can make debugging difficult• Synchronous code will slow it down • Use/Write libraries for EM
  58. 58. Worth checking out• EM-Synchrony: https://github.com/igrigorik/em-synchrony• Goliath: https://github.com/postrank-labs/goliath• Async_Sinatra: https://github.com/raggi/async_sinatra
  59. 59. Baie Dankie!
  60. 60. Questions?

×