Slide 1

Slide 1 text

DON’T FEAR THE GIL: WHAT RUBY HAS IN THE BOX FOR CONCURRENT PROGRAMMING Renan Ranelli

Slide 2

Slide 2 text

Renan Ranelli (Milhouse)

Slide 3

Slide 3 text

Software Engineer @ Renan Ranelli (Milhouse)

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

CASE STUDY - HODOR

Slide 13

Slide 13 text

CASE STUDY - HODOR

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

CONCURRENCY MODELS • Multiprocesses (resque, unicorn) • Multithreading (sidekiq, puma) • Corroutines • Fibers (Ruby has them!) • Actors (Celluloid) • Other witchcraft like CSP and process calculi

Slide 20

Slide 20 text

For now on when I say Ruby, I’m talking about the MRI (Jruby, Rubinius and friends are a completely different story) DISCLAIMER

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

foo's Local Variables foo's return Address foo's call parameters Stack Pointer HEAP

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

111 HEAP foo's Local Variables foo's return Address foo's call parameters Stack Pointer

Slide 28

Slide 28 text

1111

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

LET US TALK ABOUT THE GIL

Slide 36

Slide 36 text

LET US TALK ABOUT THE GIL BROTHER

Slide 37

Slide 37 text

THE GIL PREVENTS PARALLEL EXECUTION OF RUBY CODE. IT DOES *NOT* PREVENTS CONCURRENCY

Slide 38

Slide 38 text

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.

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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.

Slide 44

Slide 44 text

MULTITHREADING – ABSTRACTIONS ➢ Useful abstractions (All of them available @ concurrent-ruby): ➢ Thread Pools ➢ IVars ➢ Futures ➢ Promises ➢ Channels ➢ Software Transactional Memory (STM) ➢ Agents

Slide 45

Slide 45 text

THREAD POOLS

Slide 46

Slide 46 text

THREAD POOLS

Slide 47

Slide 47 text

THREAD POOLS

Slide 48

Slide 48 text

• Is a “safe to write” and “safe to read” container. Great to communicate and collaborate threads without much hassle. IVAR

Slide 49

Slide 49 text

IVAR

Slide 50

Slide 50 text

• Used to encapsulate the asynchrony of a computation. (Is closely related to async/await of languages like Scala, C#, Dart, …) FUTURES

Slide 51

Slide 51 text

FUTURES

Slide 52

Slide 52 text

FUTURES

Slide 53

Slide 53 text

FUTURES

Slide 54

Slide 54 text

Just like futures but chainable (but Monads!) PROMISES

Slide 55

Slide 55 text

You can combine an array of promises into a promise of an array: PROMISES

Slide 56

Slide 56 text

CASO DE USO - HODOR

Slide 57

Slide 57 text

REAL WORLD USE CASE

Slide 58

Slide 58 text

REAL WORLD USE CASE

Slide 59

Slide 59 text

REAL WORLD USE CASE Deploy ! Time doing actual work Time dequeuing events

Slide 60

Slide 60 text

REAL WORLD USE CASE

Slide 61

Slide 61 text

REAL WORLD USE CASE

Slide 62

Slide 62 text

REAL WORLD USE CASE • And the we grew to handle: ● Dependencies ● Conflicts ● Sharding ● Data-sensitive synchronization

Slide 63

Slide 63 text

SEEMS TO BE FUN, RIGHT ?

Slide 64

Slide 64 text

SEEMS TO BE FUN, RIGHT ?

Slide 65

Slide 65 text

SEEMS TO BE EASY, RIGHT ?

Slide 66

Slide 66 text

No content

Slide 67

Slide 67 text

No content

Slide 68

Slide 68 text

NOT QUITE.

Slide 69

Slide 69 text

LET ME SHARE SOME OF MY PAIN

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

LESSONS LEARNED ➢ OMG PLEASE DO NOT use Timeout.timeout !!111! Connection is never checked-in !!!

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

LESSONS LEARNED ➢ Keep your damn gems updated !!!

Slide 77

Slide 77 text

LESSONS LEARNED ➢ Keep your damn gems updated !!!

Slide 78

Slide 78 text

LESSONS LEARNED ➢ Keep your damn gems updated !!!

Slide 79

Slide 79 text

LESSONS LEARNED ➢ Test your stuff !

Slide 80

Slide 80 text

LESSONS LEARNED ➢ Stress Test your stuff !

Slide 81

Slide 81 text

INTEGRATE ALL THE THINGS

Slide 82

Slide 82 text

METRICS, METRICS, METRICS !

Slide 83

Slide 83 text

METRICS, METRICS, METRICS !

Slide 84

Slide 84 text

METRICS, METRICS, METRICS !

Slide 85

Slide 85 text

LESSONS LEARNED • Talk to the open source developers. Your feedback is invaluable!

Slide 86

Slide 86 text

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.

Slide 87

Slide 87 text

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

Slide 88

Slide 88 text

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

Slide 89

Slide 89 text

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

Slide 90

Slide 90 text

OBRIGADO !

Slide 91

Slide 91 text

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