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

RubyConf Brazil 2015 - Don't Fear the GIL: What...

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

Renan Ranelli

September 18, 2015
Tweet

More Decks by Renan Ranelli

Other Decks in Programming

Transcript

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

    FOR CONCURRENT PROGRAMMING Renan Ranelli
  2. 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
  3. 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
  4. 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
  5. 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
  6. CONCURRENCY MODELS • Multiprocesses (resque, unicorn) • Multithreading (sidekiq, puma)

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

    the MRI (Jruby, Rubinius and friends are a completely different story) DISCLAIMER
  8. 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
  9. 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
  10. 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
  11. 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
  12. Process Context Process Context HEAP (SHARED MEMORY) Stack2 Thread 2

    Stack3 Thread 3 Processor Core Stack1 Thread 1
  13. Process Context Process Context Processor Core Processor Core HEAP (SHARED

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

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

    Stack2 Thread 2 Stack3 Thread 3 Processor Core Processor Core
  16. 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.
  17. Process (Same address space) Process (Same address space) HEAP (SHARED

    MEMORY) Stack1 Thread 1 Stack2 Thread 2 Stack3 Thread 3 Processor Core Processor Core
  18. 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
  19. 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
  20. 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
  21. 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.
  22. MULTITHREADING – ABSTRACTIONS ➢ Useful abstractions (All of them available

    @ concurrent-ruby): ➢ Thread Pools ➢ IVars ➢ Futures ➢ Promises ➢ Channels ➢ Software Transactional Memory (STM) ➢ Agents
  23. • Is a “safe to write” and “safe to read”

    container. Great to communicate and collaborate threads without much hassle. IVAR
  24. • Used to encapsulate the asynchrony of a computation. (Is

    closely related to async/await of languages like Scala, C#, Dart, …) FUTURES
  25. REAL WORLD USE CASE • And the we grew to

    handle: • Dependencies • Conflicts • Sharding • Data-sensitive synchronization
  26. LIÇÕES APRENDIDAS • Beware of the Active Record’s connection pool.

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

    Specially if, god forbid, you’re in Rails 3 land.
  28. 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.