RubyConf Brazil 2015 - Don't Fear the GIL: What Ruby has in the box for concurrent programming

4569aec00cb223b3fbf484f9e7ba1256?s=47 Renan Ranelli
September 18, 2015

RubyConf Brazil 2015 - Don't Fear the GIL: What Ruby has in the box for concurrent programming

my talk at rubyconf brasil 2015

4569aec00cb223b3fbf484f9e7ba1256?s=128

Renan Ranelli

September 18, 2015
Tweet

Transcript

  1. DON’T FEAR THE GIL: WHAT RUBY HAS IN THE BOX

    FOR CONCURRENT PROGRAMMING Renan Ranelli
  2. Renan Ranelli (Milhouse)

  3. Software Engineer @ Renan Ranelli (Milhouse)

  4. AGENDA • Why should I care about concurrency? • How

    is concurrency different from parallelism? What the GIL does? • Why Thread#new is not the answer. • How not to repeat my mistakes
  5. WHO IS THIS TALK FOR • You, who kinda know

    what multithreading is, but don't grok it yet • You, who have no clear understanding on the difference of concurrency and parallelism
  6. WHY SHOULD I CARE ? • Concurrency enables asynchrony and

    parallelism • Free you precious CPU time to do useful stuff while IO is hanging (network, disk, yadda yadda) • Stuff goes faster, and you AWS bill might get smaller
  7. CONCURRENCY? • Concurrency, asynchrony and parallelism are different but related

    concepts that people often make big confusions about. • “Concurrency is when two tasks can start, run, and complete in overlapping time periods. It doesn’t necessarily mean they’ll ever both be running at the same instant. E.g. Multitasking in a single core machine” • “Parallelism is when tasks literally run at the same time, e.g. on a multicore processor or SIMD instructions” - Sun’s Multithreaded programming guide
  8. http://blog.golang.org/concurrency-is-not-parallelism

  9. http://blog.golang.org/concurrency-is-not-parallelism

  10. http://blog.golang.org/concurrency-is-not-parallelism

  11. None
  12. CASE STUDY - HODOR

  13. CASE STUDY - HODOR

  14. HODOR IS OUR HOME-MADE MASTER-MASTER(-ISH) REPLICATION SYSTEM

  15. None
  16. None
  17. None
  18. None
  19. CONCURRENCY MODELS • Multiprocesses (resque, unicorn) • Multithreading (sidekiq, puma)

    • Corroutines • Fibers (Ruby has them!) • Actors (Celluloid) • Other witchcraft like CSP and process calculi
  20. For now on when I say Ruby, I’m talking about

    the MRI (Jruby, Rubinius and friends are a completely different story) DISCLAIMER
  21. None
  22. foo's Local Variables foo's return Address foo's call parameters Stack

    Pointer HEAP
  23. foo's Local Variables foo's return Address foo's call parameters bar's

    Local Variables bar's Return Address bar's Call Parameters Stack Pointer HEAP
  24. foo's Local Variables foo's return Address foo's call parameters bar's

    Local Variables bar's Return Address bar's Call Parameters baz's Local Variables baz's Return Address baz's Call Parameters Stack Pointer HEAP
  25. foo's Local Variables foo's return Address foo's call parameters bar's

    Local Variables bar's Return Address bar's Call Parameters baz's Local Variables baz's Return Address baz's Call Parameters Stack Pointer 11 HEAP
  26. 11 HEAP foo's Local Variables foo's return Address foo's call

    parameters bar's Local Variables bar's Return Address bar's Call Parameters Stack Pointer
  27. 111 HEAP foo's Local Variables foo's return Address foo's call

    parameters Stack Pointer
  28. 1111

  29. Process Context Process Context HEAP (SHARED MEMORY) Stack2 Thread 2

    Stack3 Thread 3 Processor Core Stack1 Thread 1
  30. Process Context Process Context Processor Core HEAP (SHARED MEMORY) Stack1

    Thread 1 Stack2 Thread 2 Stack3 Thread 3
  31. Process Context Process Context Processor Core HEAP (SHARED MEMORY) Stack1

    Thread 1 Stack2 Thread 2 Stack3 Thread 3
  32. Process Context Process Context Processor Core Processor Core HEAP (SHARED

    MEMORY) Stack1 Thread 1 Stack2 Thread 2 Stack3 Thread 3
  33. Process Context Process Context HEAP (SHARED MEMORY) Stack1 Thread 1

    Stack2 Thread 2 Stack3 Thread 3 Processor Core Processor Core
  34. Process Context Process Context HEAP (SHARED MEMORY) Stack1 Thread 1

    Stack2 Thread 2 Stack3 Thread 3 Processor Core Processor Core
  35. LET US TALK ABOUT THE GIL

  36. LET US TALK ABOUT THE GIL BROTHER

  37. THE GIL PREVENTS PARALLEL EXECUTION OF RUBY CODE. IT DOES

    *NOT* PREVENTS CONCURRENCY
  38. LET US TALK ABOUT THE GIL ➢ The GIL (Global

    Interpreter Lock) makes it impossible to have Ruby code executing simultaneously (i.e. in parallel) in different threads. ➢ However, Ruby finds it safe to release GIL when waiting for IO. ➢ If your life is IO bound (which it probably is) this lack of true parallelism shouldn’t matter much. If it does, you’re better served elsewhere. YMMV.
  39. Process (Same address space) Process (Same address space) HEAP (SHARED

    MEMORY) Stack1 Thread 1 Stack2 Thread 2 Stack3 Thread 3 Processor Core Processor Core
  40. Process (Same address space) Process (Same address space) HEAP (SHARED

    MEMORY) Stack1 Thread 1 Stack2 Thread 2 Stack3 Thread 3 Processor Core Processor Core GIL
  41. Process (Same address space) Process (Same address space) HEAP (SHARED

    MEMORY) Stack1 Thread 1 Stack2 Thread 2 Stack3 Thread 3 Processor Core Processor Core GIL BLOCKED
  42. Process (Same address space) Process (Same address space) HEAP (SHARED

    MEMORY) Stack1 Thread 1 Stack2 Thread 2 Stack3 Thread 3 Processor Core Processor Core GIL DOING ASYNC IO
  43. MULTITHREADING • Thread#new. Just don’t. Mike Perham's words. • There

    are many abstractions available for dealing with concurrent computation. They are much more expressive and intention revealing than spinning up new Threads. • A downright excellent example is the java.util.concurrent library. In the Ruby world there is the great concurrent-ruby gem.
  44. MULTITHREADING – ABSTRACTIONS ➢ Useful abstractions (All of them available

    @ concurrent-ruby): ➢ Thread Pools ➢ IVars ➢ Futures ➢ Promises ➢ Channels ➢ Software Transactional Memory (STM) ➢ Agents
  45. THREAD POOLS

  46. THREAD POOLS

  47. THREAD POOLS

  48. • Is a “safe to write” and “safe to read”

    container. Great to communicate and collaborate threads without much hassle. IVAR
  49. IVAR

  50. • Used to encapsulate the asynchrony of a computation. (Is

    closely related to async/await of languages like Scala, C#, Dart, …) FUTURES
  51. FUTURES

  52. FUTURES

  53. FUTURES

  54. Just like futures but chainable (but Monads!) PROMISES

  55. You can combine an array of promises into a promise

    of an array: PROMISES
  56. CASO DE USO - HODOR

  57. REAL WORLD USE CASE

  58. REAL WORLD USE CASE

  59. REAL WORLD USE CASE Deploy ! Time doing actual work

    Time dequeuing events
  60. REAL WORLD USE CASE

  61. REAL WORLD USE CASE

  62. REAL WORLD USE CASE • And the we grew to

    handle: • Dependencies • Conflicts • Sharding • Data-sensitive synchronization
  63. SEEMS TO BE FUN, RIGHT ?

  64. SEEMS TO BE FUN, RIGHT ?

  65. SEEMS TO BE EASY, RIGHT ?

  66. None
  67. None
  68. NOT QUITE.

  69. LET ME SHARE SOME OF MY PAIN

  70. LESSONS LEARNED ➢ OMG PLEASE DO NOT use Timeout.timeout !!111!

  71. LESSONS LEARNED ➢ OMG PLEASE DO NOT use Timeout.timeout !!111!

  72. LESSONS LEARNED ➢ OMG PLEASE DO NOT use Timeout.timeout !!111!

  73. LESSONS LEARNED ➢ OMG PLEASE DO NOT use Timeout.timeout !!111!

    Connection is never checked-in !!!
  74. LIÇÕES APRENDIDAS • Beware of the Active Record’s connection pool.

    Specially if, god forbid, you’re in Rails 3 land.
  75. LIÇÕES APRENDIDAS • Beware of the Active Record’s connection pool.

    Specially if, god forbid, you’re in Rails 3 land.
  76. LESSONS LEARNED ➢ Keep your damn gems updated !!!

  77. LESSONS LEARNED ➢ Keep your damn gems updated !!!

  78. LESSONS LEARNED ➢ Keep your damn gems updated !!!

  79. LESSONS LEARNED ➢ Test your stuff !

  80. LESSONS LEARNED ➢ Stress Test your stuff !

  81. INTEGRATE ALL THE THINGS

  82. METRICS, METRICS, METRICS !

  83. METRICS, METRICS, METRICS !

  84. METRICS, METRICS, METRICS !

  85. LESSONS LEARNED • Talk to the open source developers. Your

    feedback is invaluable!
  86. LESSONS LEARNED • To avoid problems such as those that

    made Milhouse sad: 1. Don’t do concurrent programming. 2. If you have to, don’t share data between threads (Immutable data structures! Yay!). Don’t decide to go such route before MEASURING YOUR STUFF AND MAKING SURE YOU ACTUALLY NEED IT. 3. If you have to share data, use the many battle-proven libraries for doing so. Atomics, IVars, MVars are your friends.
  87. LESSONS LEARNED STOP USING Ruby’s Timeout#timeout RIGHT NOW.

  88. LESSONS LEARNED STOP USING Ruby’s Timeout#timeout RIGHT NOW.

  89. LESSONS LEARNED STOP USING Ruby’s Timeout#timeout RIGHT NOW.

  90. OBRIGADO !

  91. @renanranelli /rranelli Renan Ranelli (Milhouse) milhouseonsofware.com