Slide 1

Slide 1 text

Play with Ruby Threads

Slide 2

Slide 2 text

Ruby Program Fetch URL A Fetch URL B End Program

Slide 3

Slide 3 text

Ruby Program Fetch URL A Fetch URL B End Program

Slide 4

Slide 4 text

require 'net/http' ! t1 = Thread.new { ! content = Net::HTTP.get(URI.parse("http://google.com")) puts "I just fetched google.com" } ! t2 = Thread.new { ! content = Net::HTTP.get(URI.parse("http://github.com")) puts "I just fetched github.com" } ! t1.join && t2.join puts "I've finished executing everything"

Slide 5

Slide 5 text

› time ruby threads.rb! I just fetched google.com! I just fetched github.com! I've finished executing everything! ruby threads.rb 0.13s user 0.06s system 40% cpu 0.450 total

Slide 6

Slide 6 text

require 'net/http' ! content = Net::HTTP.get(URI.parse("http://google.com")) puts "I just fetched google.com" ! content = Net::HTTP.get(URI.parse("http://github.com")) puts "I just fetched github.com" ! puts "I've finished executing everything"

Slide 7

Slide 7 text

time ruby no_threads.rb! I just fetched google.com! I just fetched github.com! I've finished executing everything! ruby no_thread.rb 0.12s user 0.06s system 6% cpu 2.698 total

Slide 8

Slide 8 text

2.698 0.450 5.99

Slide 9

Slide 9 text

Lifecycle of a thread

Slide 10

Slide 10 text

Thread.new • Thread.new { … }! • Thread.fork { … }! • Thread.start(1, 2) { |x, y| … }

Slide 11

Slide 11 text

Thread#join thread = Thread.new { sleep 3 } thread.join

Slide 12

Slide 12 text

Thread#value thread = Thread.new do 400 + 5 end puts thread.value #=> 405

Slide 13

Slide 13 text

Thread#status thread = Thread.new do Thread.current.status #=> 'run' 2 * 3 end puts thread.status #=> 'run' thread.join puts thread.status #=> false

Slide 14

Slide 14 text

Thread#stop thread = Thread.new do Thread.stop puts 'Hello there' end ! # wait for the thread to trigger its stop nil until thread.status == 'sleep' thread.wakeup thread.join

Slide 15

Slide 15 text

Thread Safety

Slide 16

Slide 16 text

Non-deterministic context switching • In order to provide fair access, the thread scheduler can pause a thread at any time

Slide 17

Slide 17 text

Non-deterministic context switching class Post ! def comments @comments ||= [] end end

Slide 18

Slide 18 text

Non-deterministic context switching class Post ! def comments if @comments.nil? temp = [] @comments = temp end end end

Slide 19

Slide 19 text

Non-deterministic context switching class Post def initialize @comments_mutex = Mutex.new end ! def comments @comments_mutex.synchronize do @comments ||= [] end end end

Slide 20

Slide 20 text

MRI’s GIL MRI has something called a global interpreter lock (GIL).! It's a lock around the execution of Ruby code.! This means that in a multi-threaded context, only one thread can execute Ruby code at any one time.

Slide 21

Slide 21 text

MRI’s GIL So if you have 8 threads busily working on a 8-core machine, only one thread and one core will be busy at any given time.! The GIL exists to protect Ruby internals from race conditions that could corrupt data.! There are caveats and optimizations, but this is the gist.

Slide 22

Slide 22 text

How many threads should I use? • Is your program IO or CPU bound?! • IO Bound will allow a lot of threads! • CPU Bound will depend of the number of cores! • The only way is to measure

Slide 23

Slide 23 text

Resources

Slide 24

Slide 24 text

http://ruby-doc.org/ core-2.1.0/Thread.html

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

http://bit.ly/ruby-threads