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

Concurrent systems in Ruby

6c469749d725177dd2837d806c769cd4?s=47 Jonas Nicklas
September 27, 2014

Concurrent systems in Ruby

Slides from my talk at RailsClub.

For the longest time, Ruby has been criticized for its underwhelming concurrency story, but things have changed, Ruby has changed.
In this talk I will showcase a few different options for concurrency, including the classic mutex/condition variable combo, Node style evented IO, Clojure-style compare-and-set, and Erlang-style actors. I will show you how you can use each of these in Ruby, and how Ruby gives you more choice than most other platforms when it comes to concurrency.

I will give you an introduction to Celluloid, the premiere framework for building concurrent applications in Ruby, showing you how it really works and how it combines the best of all options into one cohesive solution.

6c469749d725177dd2837d806c769cd4?s=128

Jonas Nicklas

September 27, 2014
Tweet

Transcript

  1. Concurrent systems in Ruby Jonas Nicklas, Elabs

  2. None
  3. What is concurrency?

  4. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ut

    lorem id nulla efficitur bibendum tempus rutrum velit. Aenean sagittis pretium porttitor. Praesent blandit, ex in gravida feugiat, felis leo consectetur nulla, quis fermentum nunc leo id metus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vestibulum sed iaculis purus, ut tristique velit. Maecenas consectetur rhoncus nisi, quis sollicitudin enim rhoncus eget. Duis in ex in metus ullamcorper euismod. Integer nulla est, maximus quis dapibus a, fermentum a lorem. Fusce ut ullamcorper lorem. Proin tempus interdum sodales. Aenean sed arcu iaculis, imperdiet lacus sed, faucibus diam. ! Aliquam nec neque magna. Vestibulum sit amet sollicitudin arcu, eget viverra magna. Duis pharetra ullamcorper ipsum, eu convallis odio ultrices eget. Praesent pulvinar lorem felis, in tristique tellus volutpat posuere. Donec porttitor turpis sit amet eros lacinia fermentum in nec turpis. Duis id sagittis turpis, sed accumsan est. Vestibulum tincidunt sit amet eros quis sagittis. Vivamus sit amet felis ut est varius ornare id sed leo. Donec at metus mi. Vivamus euismod purus quis sem tristique maximus. ! Phasellus commodo purus vel ipsum porttitor, in ultrices ante aliquam. Donec tempor mi quis nunc condimentum varius. Curabitur euismod sagittis porta. Maecenas fringilla, lectus ut laoreet euismod, enim erat rhoncus orci, vitae lobortis nibh eros volutpat odio. Morbi ac mauris eu arcu viverra placerat. Vestibulum eget ex euismod, faucibus velit sit amet, luctus ligula. Vivamus massa tortor, fringilla vitae neque nec, aliquam consequat nulla. Integer pellentesque viverra tristique. Nunc varius semper aliquet. Proin quis sagittis neque, quis tristique justo. ! Integer neque tellus, fermentum in purus vel, euismod blandit metus. In ac dolor sit amet est sodales ultrices. Sed quis nisl nec lacus porttitor lobortis quis tincidunt massa. Suspendisse accumsan enim diam, ut tincidunt augue placerat et. Curabitur faucibus, orci vitae hendrerit cursus, lectus leo vulputate tellus, hendrerit pulvinar ex lorem eget augue. Praesent sagittis sodales volutpat. Aenean tempus velit commodo quam iaculis, vel condimentum nunc ultrices. Phasellus eget nisi nec leo consectetur accumsan. Curabitur dignissim placerat purus vel euismod. Vestibulum luctus vel neque eu suscipit. Nulla eget neque ipsum. Suspendisse id mauris sit amet mauris faucibus ornare. Integer commodo placerat lacinia. Sed sollicitudin risus a nisl sagittis aliquet. Suspendisse at quam ipsum. Sed augue ligula, maximus nec blandit ut, bibendum quis nibh. ! Phasellus in commodo massa. Donec tincidunt, tellus ut condimentum aliquet, orci odio elementum justo, a tempus purus quam eget sem. Cras commodo justo arcu, non efficitur orci luctus nec. Ut sit amet varius libero. Suspendisse quis nibh vel tellus auctor tempus. Vestibulum sagittis felis pellentesque neque eleifend, quis pellentesque purus ornare. Sed finibus libero id malesuada tempor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ut lorem id nulla efficitur bibendum tempus rutrum velit. Aenean sagittis pretium porttitor. Praesent blandit, ex in gravida feugiat, felis leo consectetur nulla, quis fermentum nunc leo id metus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vestibulum sed iaculis purus, ut tristique velit. Maecenas consectetur rhoncus nisi, quis sollicitudin enim rhoncus eget. Duis in ex in metus ullamcorper euismod. Integer nulla est, maximus quis dapibus a, fermentum a lorem. Fusce ut ullamcorper lorem. Proin tempus interdum sodales. Aenean sed arcu iaculis, imperdiet lacus sed, faucibus diam. ! Aliquam nec neque magna. Vestibulum sit amet sollicitudin arcu, eget viverra magna. Duis pharetra ullamcorper ipsum, eu convallis odio ultrices eget. Praesent pulvinar lorem felis, in tristique tellus volutpat posuere. Donec porttitor turpis sit amet eros lacinia fermentum in nec turpis. Duis id sagittis turpis, sed accumsan est. Vestibulum tincidunt sit amet eros quis sagittis. Vivamus sit amet felis ut est varius ornare id sed leo. Donec at metus mi. Vivamus euismod purus quis sem tristique maximus. ! Phasellus commodo purus vel ipsum porttitor, in ultrices ante aliquam. Donec tempor mi quis nunc condimentum varius. Curabitur euismod sagittis porta. Maecenas fringilla, lectus ut laoreet euismod, enim erat rhoncus orci, vitae lobortis nibh eros volutpat odio. Morbi ac mauris eu arcu viverra placerat. Vestibulum eget ex euismod, faucibus velit sit amet, luctus ligula. Vivamus massa tortor, fringilla vitae neque nec, aliquam consequat nulla. Integer pellentesque viverra tristique. Nunc varius semper aliquet. Proin quis sagittis neque, quis tristique justo. ! Integer neque tellus, fermentum in purus vel, euismod blandit metus. In ac dolor sit amet est sodales ultrices. Sed quis nisl nec lacus porttitor lobortis quis tincidunt massa. Suspendisse accumsan enim diam, ut tincidunt augue placerat et. Curabitur faucibus, orci vitae hendrerit cursus, lectus leo vulputate tellus, hendrerit pulvinar ex lorem eget augue. Praesent sagittis sodales volutpat. Aenean tempus velit commodo quam iaculis, vel condimentum nunc ultrices. Phasellus eget nisi nec leo consectetur accumsan. Curabitur dignissim placerat purus vel euismod. Vestibulum luctus vel neque eu suscipit. Nulla eget neque ipsum. Suspendisse id mauris sit amet mauris faucibus ornare. Integer commodo placerat lacinia. Sed sollicitudin risus a nisl sagittis aliquet. Suspendisse at quam ipsum. Sed augue ligula, maximus nec blandit ut, bibendum quis nibh. ! Phasellus in commodo massa. Donec tincidunt, tellus ut condimentum aliquet, orci odio elementum justo, a tempus purus quam eget sem. Cras commodo justo arcu, non efficitur orci luctus nec. Ut sit amet varius libero. Suspendisse quis nibh vel tellus auctor tempus. Vestibulum sagittis felis pellentesque neque eleifend, quis pellentesque purus ornare. Sed finibus libero id malesuada tempor.
  5. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ut

    lorem id nulla efficitur bibendum tempus rutrum velit. Aenean sagittis pretium porttitor. Praesent blandit, ex in gravida feugiat, felis leo consectetur nulla, quis fermentum nunc leo id metus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vestibulum sed iaculis purus, ut tristique velit. Maecenas consectetur rhoncus nisi, quis sollicitudin enim rhoncus eget. Duis in ex in metus ullamcorper euismod. Integer nulla est, maximus quis dapibus a, fermentum a lorem. Fusce ut ullamcorper lorem. Proin tempus interdum sodales. Aenean sed arcu iaculis, imperdiet lacus sed, faucibus diam.
  6. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ut

    lorem id nulla efficitur bibendum tempus rutrum velit. Aenean sagittis pretium porttitor. Praesent blandit, ex in gravida feugiat, felis leo consectetur nulla, quis fermentum nunc leo id metus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vestibulum sed iaculis purus, ut tristique velit. Maecenas consectetur rhoncus nisi, quis sollicitudin enim rhoncus eget. Duis in ex in metus ullamcorper euismod. Integer nulla est, maximus quis dapibus a, fermentum a lorem. Fusce ut ullamcorper lorem. Proin tempus interdum sodales. Aenean sed arcu iaculis, imperdiet lacus sed, faucibus diam. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ut lorem id nulla efficitur bibendum tempus rutrum velit. Aenean sagittis pretium porttitor. Praesent blandit, ex in gravida feugiat, felis leo consectetur nulla, quis fermentum nunc leo id metus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vestibulum sed iaculis purus, ut tristique velit. Maecenas consectetur rhoncus nisi, quis sollicitudin enim rhoncus eget. Duis in ex in metus ullamcorper euismod. Integer nulla est, maximus quis dapibus a, fermentum a lorem. Fusce ut ullamcorper lorem. Proin tempus interdum sodales. Aenean sed arcu iaculis, imperdiet lacus sed, faucibus diam.
  7. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ut

    lorem id nulla efficitur bibendum tempus rutrum velit. Aenean sagittis pretium porttitor. Praesent blandit, ex in gravida feugiat, felis leo consectetur nulla, quis fermentum nunc leo id metus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vestibulum sed iaculis purus, ut tristique velit. Maecenas consectetur rhoncus nisi, quis sollicitudin enim rhoncus eget. Duis in ex in metus ullamcorper euismod. Integer nulla est, maximus quis dapibus a, fermentum a lorem. Fusce ut ullamcorper lorem. Proin tempus interdum sodales. Aenean sed arcu iaculis, imperdiet lacus sed, faucibus diam. ! Aliquam nec neque magna. Vestibulum sit amet sollicitudin arcu, eget viverra magna. Duis pharetra ullamcorper ipsum, eu convallis odio ultrices eget. Praesent pulvinar lorem felis, in tristique tellus volutpat posuere. Donec porttitor turpis sit amet eros lacinia fermentum in nec turpis. Duis id sagittis turpis, sed accumsan est. Vestibulum tincidunt sit amet eros quis sagittis. Vivamus sit amet felis ut est varius ornare id sed leo. Donec at metus mi. Vivamus euismod purus quis sem tristique maximus. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ut lorem id nulla efficitur bibendum tempus rutrum velit. Aenean sagittis pretium porttitor. Praesent blandit, ex in gravida feugiat, felis leo consectetur nulla, quis fermentum nunc leo id metus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vestibulum sed iaculis purus, ut tristique velit. Maecenas consectetur rhoncus nisi, quis sollicitudin enim rhoncus eget. Duis in ex in metus ullamcorper euismod. Integer nulla est, maximus quis dapibus a, fermentum a lorem. Fusce ut ullamcorper lorem. Proin tempus interdum sodales. Aenean sed arcu iaculis, imperdiet lacus sed, faucibus diam. Concurrency Switching between multiple tasks
  8. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ut

    lorem id nulla efficitur bibendum tempus rutrum velit. Aenean sagittis pretium porttitor. Praesent blandit, ex in gravida feugiat, felis leo consectetur nulla, quis fermentum nunc leo id metus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vestibulum sed iaculis purus, ut tristique velit. Maecenas consectetur rhoncus nisi, quis sollicitudin enim rhoncus eget. Duis in ex in metus ullamcorper euismod. Integer nulla est, maximus quis dapibus a, fermentum a lorem. Fusce ut ullamcorper lorem. Proin tempus interdum sodales. Aenean sed arcu iaculis, imperdiet lacus sed, faucibus diam. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc ut lorem id nulla efficitur bibendum tempus rutrum velit. Aenean sagittis pretium porttitor. Praesent blandit, ex in gravida feugiat, felis leo consectetur nulla, quis fermentum nunc leo id metus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vestibulum sed iaculis purus, ut tristique velit. Maecenas consectetur rhoncus nisi, quis sollicitudin enim rhoncus eget. Duis in ex in metus ullamcorper euismod. Integer nulla est, maximus quis dapibus a, fermentum a lorem. Fusce ut ullamcorper lorem. Proin tempus interdum sodales. Aenean sed arcu iaculis, imperdiet lacus sed, faucibus diam. Parallelism Performing multiple tasks at the same time
  9. Single CPU Concurrent but not Parallel

  10. We can have Concurrency without Parallelism

  11. Ruby MRI GIL (Global Interpreter Lock) prevents parallelism (but not

    concurrency)
  12. JRuby and Rubinius no GIL Concurrent and Parallel

  13. Switch between tasks

  14. the Scheduler

  15. Time Scheduler Alternative 1

  16. Time Task A I’m done! Scheduler Alternative 1

  17. Time Task A Task B I’m done! Scheduler Alternative 1

  18. Time Task A Task B Task A Scheduler I’m done!

    Alternative 1
  19. co-operative multitasking

  20. Time Scheduler Problem

  21. Run Task A! Time Task A LOL!!! Scheduler Problem

  22. Time Scheduler Alternative 2

  23. Time Task A Scheduler ZAP! Alternative 2

  24. Time Task A Task B Scheduler ZAP! Alternative 2

  25. Time Task A Task B Task A Scheduler ZAP! Alternative

    2
  26. pre-emptive multitasking

  27. unpredictable Context-switches

  28. Our code can be suspended at any point in time

    (in a pre-emptively scheduled system)
  29. Processes isolated memory Task A Task B

  30. Task A Task B (possibly) shared memory shared Threads

  31. What is a thread?

  32. duplicated memory duplicated duplicated Processes Task A Task B

  33. x = x + 1

  34. x = 0 ! 100.times.map do Thread.new do x =

    x + 1 end end.each(&:join) ! puts x
  35. read value increase value write value back

  36. Thread A Thread B Integer value read value ← 0

    increase value 0 write back → 1 read value ← 1 increase value 1 write back → 2 source: wikipedia.org
  37. Thread A Thread B Integer value read value ← 0

    read value ← 0 increase value 0 increase value 0 write back → 1 write back → 1 source: wikipedia.org
  38. Race-condition

  39. Ruby doesn’t protect you

  40. Don’t share mutable state

  41. Celluloid Idiomatic Ruby code https://github.com/celluloid/celluloid

  42. class Counter attr_reader :value ! def initialize @value = 0

    end ! def increment @value += 1 end end
  43. class Counter attr_reader :value ! def initialize @value = 0

    end ! def increment @value += 1 end end
  44. require "celluloid" ! class Counter include Celluloid ! attr_reader :value

    ! def initialize @value = 0 end ! def increment @value += 1 end end
  45. Mutual Exclusion Lock a.k.a Mutex Pessimistic Lock

  46. class Counter attr_reader :value ! def initialize @mutex = Mutex.new

    @value = 0 end ! def increment @mutex.synchronize do @value += 1 end end end
  47. Atomic Optimistic Lock

  48. class Counter attr_reader :value ! def initialize @value = Atomic.new(0)

    end ! def increment @value.update do |x| x + 1 end end end
  49. Atoms + Persistent datastructures = ♥ (Clojure style concurrency)

  50. Hamster https://github.com/hamstergem/hamster Atomic https://github.com/ruby-concurrency/atomic Concurrent Ruby https://github.com/ruby-concurrency/concurrent-ruby

  51. Green vs Native

  52. Node.js Green Threads

  53. Node.js collaboratively scheduled not parallel* * ignoring workers

  54. var x = 0; ! x = x + 1;

    // safe ! setTimeout(function() { // context switch here x = x + 1; // safe }, 100); ! setTimeout(function() { // context switch here x = x + 1; // safe }, 100);
  55. Compromise

  56. Erlang Cheap Green Threads

  57. Ruby 1.8 Green Threads (they sucked)

  58. Ruby 1.9+ Native Threads (yay!)

  59. Ruby 1.9+ Fibers

  60. Manual control co-operative scheduling

  61. Fibers are “lightweight” (but it comes at a price)

  62. Tasks need Stacks

  63. Fibers have small stacks

  64. Rails + Fibers = :(

  65. UNIX Processes

  66. Multiple UNIX Processes e.g. Passenger or Unicorn

  67. Rails (Processes) Server Process Process Process Process Requests application code

    request specific data application code request specific data
  68. Rails (threads) Server Thread Thread Thread Thread Requests application code

    request specific data
  69. Rails (copy-on-write) Server Process Process Process Process Requests application code

    request specific data
  70. Platform Parallel Multitasking Scheduler Memory Isolation Ruby Threads (MRI 1.8)

    no pre-emptive green no Ruby Threads (MRI 1.9+) no pre-emptive native no Ruby Threads (JRuby, Rubinius) yes pre-emptive native no Ruby Fibers no collaborative green no Node.js no collaborative green no Erlang yes pre-emptive green yes UNIX processes (e.g. Unicorn) yes pre-emptive native yes Go (Goroutines) yes pre-emptive green no Clojure yes pre-emptive native immutable
  71. Celluloid

  72. require "celluloid" ! class Counter include Celluloid ! attr_reader :value

    ! def initialize @value = 0 end ! def increment @value += 1 end end
  73. Each Instance has its own pre-emptively scheduled Native Thread

  74. >> counter = Counter.new => #<Celluloid::CellProxy(Counter:0x48a8) @value=0> >> counter.thread =>

    #<Celluloid::ThreadHandle:0x48dc @mutex=#<Mutex:0x48e0 @owner=nil> @thread=#<Celluloid::Thread:0x48e8 id=8 sleep> @join=#<ConditionVariable:0x48ec @waiters=[]>>
  75. Each Actor has its own Collaborative Scheduler

  76. Each method call to an Actor Has its own (collaboratively

    scheduled) Task
  77. Celluloid calls context-switches “pipelining”

  78. Celluloid pipelines if…. 1. Making a synchronous call from one

    actor to another 2. Any I/O operations when using Celluloid::IO or Celluloid::ZMQ 3. Waiting for the result of a future 4. Sleeping using Celluloid#sleep 5. Waiting for a condition 6. Receiving a raw asynchronous message using the receive method source: https://github.com/celluloid/celluloid/wiki/Pipelining-and-execution-modes
  79. Regular I/O blocks!

  80. require "celluloid" ! class Counter include Celluloid ! attr_reader :value

    ! def initialize @other = OtherActor.new @value = 0 end ! def increment @other.some_method # context switch here @value += 1 end end
  81. require "celluloid" ! class Counter include Celluloid ! attr_reader :value

    ! def initialize @other = link(Actor[:some_other_actor]) @value = 0 end ! exclusive :increment def increment @other.call_some_method # no context switch! @value += 1 end end
  82. require "celluloid" ! class Counter include Celluloid ! attr_reader :value

    ! def initialize @other = OtherActor.new @value = 0 end ! def increment @other.some_method # context switch here @value += 1 end end
  83. Errors

  84. require "celluloid/autostart" ! class TimeBomb include Celluloid ! def initialize

    @count = 5 every(1) { ping } end ! def ping @count -= 1 raise "boom!" if @count == 0 puts "tick!" end end ! TimeBomb.supervise_as(:time_bomb)
  85. $ ruby -r ./time_bomb.rb -e sleep tick! tick! tick! tick!

    E, [2014-09-25T20:16:12.436596 #26881] ERROR -- : Actor crashed! RuntimeError: boom! tick! tick! tick! tick! E, [2014-09-25T20:16:17.446067 #26881] ERROR -- : Actor crashed! RuntimeError: boom! tick! …
  86. class RoadRunner include Celluloid ! def initialize @time_bomb = TimeBomb.new_link

    puts "MEEP" end end ! RoadRunner.supervise_as(:road_runner)
  87. $ ruby -r ./road_runner.rb -e sleep MEEP tick! tick! tick!

    tick! E, [2014-09-25T20:23:04.201099 #26976] ERROR -- : Actor crashed! RuntimeError: boom! MEEP tick! tick! tick! tick! E, [2014-09-25T20:23:09.211179 #26976] ERROR -- : Actor crashed! RuntimeError: boom! MEEP tick! …
  88. class RoadRunner include Celluloid ! trap_exit :ignore ! def initialize

    @time_bomb = TimeBomb.new_link puts "MEEP" end ! def ignore(actor, error) puts "Bomb exploded" end end ! RoadRunner.supervise_as(:road_runner)
  89. $ ruby -r ./road_runner.rb -e sleep MEEP tick! tick! tick!

    tick! E, [2014-09-25T20:27:45.909766 #27045] ERROR -- : Actor crashed! RuntimeError: boom! Bomb exploded
  90. class RoadRunner include Celluloid ! finalizer :death ! def initialize

    @time_bomb = TimeBomb.new_link puts "MEEP" end ! def death puts "Goodbye cruel world!" end end ! RoadRunner.supervise_as(:road_runner)
  91. $ ruby -r ./road_runner.rb -e sleep MEEP tick! tick! tick!

    tick! E, [2014-09-25T20:35:23.649306 #27151] ERROR -- : Actor crashed! RuntimeError: boom! Goodbye cruel world! MEEP tick! tick!
  92. Supervision Hierarchies

  93. More!

  94. Celluloid https://github.com/celluloid/celluloid Hamster https://github.com/hamstergem/hamster Atomic https://github.com/ruby-concurrency/atomic Concurrent Ruby https://github.com/ruby-concurrency/concurrent-ruby

  95. None
  96. None
  97. THANKS! Jonas Nicklas, Elabs – @jonicklas