Upgrade to Pro — share decks privately, control downloads, hide ads and more …

RubyFuZa 2012 - EventMachine

RubyFuZa 2012 - EventMachine

Lightning overview of EventMachine

autonomous

March 05, 2012
Tweet

More Decks by autonomous

Other Decks in Programming

Transcript

  1. • Mostly IO bound • Handle thousands concurrent connections •

    Stream data • Real time data delivery • You’ve got Mad Ruby Skills Monday 05 March 12
  2. What is EventMachine? • Toolkit for creating evented applications •

    Implementation of the Reactor Pattern • MRI, YARV, jRuby, Rubinius Monday 05 March 12
  3. Reactor pattern “Event handling pattern for handling service requests delivered

    concurrently to a service handler by one or more inputs. The service handler then demultiplexes the incoming requests and dispatches them synchronously to the associated request handlers.” http://en.wikipedia.org/wiki/Reactor_pattern Monday 05 March 12
  4. Http Keyboard Udp etc Demultiplexer Event Handler A Event Handler

    B Event Handler C Event Handler D Service handler Event dispatcher Monday 05 March 12
  5. Http Keyboard Udp etc Demultiplexer Event Handler A Event Handler

    B Event Handler C Event Handler D Service handler Event dispatcher Monday 05 March 12
  6. Http Keyboard Udp etc Demultiplexer Event Handler A Event Handler

    B Event Handler C Event Handler D Service handler Event dispatcher Thread 1 Thread 2 Thread 20 ... Monday 05 March 12
  7. Benefits • Application code separate from reactor • Non blocking

    IO • Single process • No threads! Monday 05 March 12
  8. Teh Basics • EM.run • EM.connection • EM.next_tick • EM.defer

    • EM::Queue • EM::Channel Monday 05 March 12
  9. Teh Basics • EM.run • EM.connection • EM.next_tick • EM.defer

    • EM::Queue • EM::Channel Monday 05 March 12
  10. ... don’t do this! • big ass loops • 1_000_000.times{}

    • while condition? • sleep • blocking IO Monday 05 March 12
  11. Teh Basics • EM.run • EM.connection • EM.next_tick • EM.defer

    • EM::Queue • EM::Channel Monday 05 March 12
  12. class EchoServer < EM::Connection def post_init puts "New connection" end

    def unbind puts "Connection closed" end def receive_data(data) send_data ">> #{data}" end end EM.run do EM.start_server('127.0.0.1', 9000, EchoServer) puts "Started server at 127.0.0.1:9000" end Monday 05 March 12
  13. class EchoServer < EM::Connection def post_init puts "New connection" end

    def unbind puts "Connection closed" end def receive_data(data) send_data ">> #{data}" end end EM.run do EM.start_server('127.0.0.1', 9000, EchoServer) puts "Started server at 127.0.0.1:9000" end # $ telnet localhost 9000 # Hello # >> Hello # Bye # >> Bye Monday 05 March 12
  14. # TCP EM.run do EM.start_server('127.0.0.1', 9000, EchoServer) end # UDP

    EM.run do EM.open_datagram_socket('127.0.0.1', 9000, EchoServer) end # Unix-domain server EM.run do EM.start_unix_domain_server('/tmp/sock', nil, EchoServer) end Monday 05 March 12
  15. 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}" end end EM.run do EM.connect('127.0.0.1', 9000, EchoClient) end Monday 05 March 12
  16. 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}" end end EM.run do EM.connect('127.0.0.1', 9000, EchoClient) end Monday 05 March 12
  17. Teh Basics • EM.run • EM.connection • EM.next_tick • EM.defer

    • EM::Queue • EM::Channel Monday 05 March 12
  18. Teh Basics • EM.run • EM.connection • EM.next_tick • EM.defer

    • EM::Queue • EM::Channel Monday 05 March 12
  19. EM.run do EM.defer do send_email( user1 ) end EM.defer do

    send_email( user2 ) end EM.defer do send_email( user3 ) end end Monday 05 March 12
  20. 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 Monday 05 March 12
  21. Teh Basics • EM.run • EM.connection • next_tick; add_timer; add_periodic_timer

    • EM.defer • EM::Queue • EM::Channel Monday 05 March 12
  22. EM.run do queue = EM::Queue.new # ... queue.push( data1, data2

    ) # ... queue.pop { |data| puts data } # >> data1 end Monday 05 March 12
  23. EM.run do queue = EM::Queue.new EM.defer do sleep( 2 )

    queue.push( '[email protected]' ) sleep( 3 ) queue.push( '[email protected]') end welcomer = Proc.new do |email| send_welcome( email ) EM.next_tick( queue.pop(&welcomer) ) end queue.pop(&welcomer); end Monday 05 March 12
  24. Teh Basics • EM.run • EM.connection • EM.next_tick • EM.defer

    • EM::Queue • EM::Channel Monday 05 March 12
  25. 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 end end Monday 05 March 12
  26. Deferrable • Light weight concurrency • Delayed execution with triggers

    • :succeeded • :failed • nil • callback and errback Monday 05 March 12
  27. 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) end end Monday 05 March 12
  28. 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) end end EM.run do s1 = LoanRequest.new('Marc') s1.approved! s2 = LoanRequest.new('Chris') EM.add_timer(2){ s2.denied! } end Monday 05 March 12
  29. 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) end end EM.run do s1 = LoanRequest.new('Marc') s1.approved! s2 = LoanRequest.new('Chris') EM.add_timer(2){ s2.denied! } end # :00 Approved Marc! # :02 Denied Chris! Monday 05 March 12
  30. 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 end end Monday 05 March 12
  31. 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 end end EM.run do m = Mailer.new m.add_mailing(1) m.add_mailing(2) m.connection_open! EM.add_timer(1) do m.connection_lost! EM.add_timer(2) do m.add_mailing(3) m.add_mailing(4) m.connection_open! end end end Monday 05 March 12
  32. 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 end end EM.run do m = Mailer.new m.add_mailing(1) m.add_mailing(2) m.connection_open! EM.add_timer(1) do m.connection_lost! EM.add_timer(2) do m.add_mailing(3) m.add_mailing(4) m.connection_open! end end end # Open connection # Sent 1 # Sent 2 # Lost connection # Open connection # Sent 3 # Sent 4 Monday 05 March 12
  33. Gotchas • Inverted flow of control can make debugging difficult

    • Synchronous code will slow it down • Use/Write libraries for EM Monday 05 March 12