This document discusses concurrency in Ruby. It begins by explaining that most modern computer architectures use multiple processors or cores, requiring programs to be parallelized to take advantage of this. It then discusses different approaches to concurrency in Ruby including processes, threads, fibers, and actors. It also covers challenges with shared state and different languages that take functional or message-passing approaches to make concurrency easier.
4. “... for the first time in history, no one is building a
much faster sequential processor. If you want your
programs to run significantly faster (...) you’re going
to have to parallelize your program.”
Hennessy and Patterson “Computer Architectures” (4th
edition, 2007)
Thursday 21 October 2010
5. But ...
forget all that
(mostly)
Thursday 21 October 2010
6. Your program
language VM
OS
(kernel processes, other processes)
multicore - multiCPU
Thursday 21 October 2010
10. Scheduling
• preemptive -> thread is told to yield
(by kernel or other thread)
• cooperative -> thread yields control
Thursday 21 October 2010
11. Processes, Threads
memory space RAM memory space
Process 1 Process 2
thread1 thread2 t1 t2 t3
scheduler (OS)
CPU CPU
Thursday 21 October 2010
12. Ruby
• Process
• Thread - green in MRI 1.8, native
threads in MRI 1.9, Rubinius, JRuby
Thursday 21 October 2010
13. MRI: GIL
• only one thread is executed at a time
• fair scheduling: timer thread!
(10 μs for Linux, 10 ms for Windows)
• blocking region to allow limited
concurrency
Thursday 21 October 2010
14. MRI: GIL
from http://www.igvita.com/2008/11/13/concurrency-is-a-myth-in-ruby/ @igrigorik
Thursday 21 October 2010
15. Other Rubies
• @evanphx working on removing the
GIL on Rubinius (Hydra branch)
• JRuby, IronRuby, MacRuby don’t have
GIL
Thursday 21 October 2010
21. Ruby threads
def execute(&block)
sorted = nil
thread = Thread.new do
sorted = block.call
end
thread.join
sorted
end
Thursday 21 October 2010
22. Fibers
• cooperative scheduling
• coroutines
• for MRI: lightweight
• JRuby, Rubinius: Fiber mapped to
native thread
Thursday 21 October 2010
23. Ruby: Coroutines
require 'fiber'
# coroutines
ary = []
f2 = nil
f1 = Fiber.new{ output:
puts "please give your login" please give your login
login = f2.transfer johndoe
puts login
puts "give password"
give password
pass = f2.transfer ultrasecret
puts pass ***** no cigar *****
f2.transfer
f2.transfer('***** no cigar *****')
}
f2 = Fiber.new{
f1.transfer('johndoe')
f1.transfer('ultrasecret')
answer = f1.transfer
puts answer
}
vaguely inspired by http://sheddingbikes.com/posts/1287306747.html
f1.resume
Thursday 21 October 2010
24. MVM
Rubinius (2008): no parallel execution
of threads in one VM ... so let’s create
one VM per native thread
vm = Rubinius::VM.spawn "blah", "-e", "puts 'hellon'"
Thursday 21 October 2010
26. shared state:
will melt your brain
• non-determinism
• atomicity
• deadlock
• livelock
• fairness/starvation
• race conditions
Thursday 21 October 2010
27. actor model
• named actors: have no shared state
• asynchronous message passing (fire
and forget)
Thursday 21 October 2010
28. CSP
• member of family of Process Calculi
(mathematical theory)
• events, processes
• synchronous (rendez-vous) message passing
• named channels - dual to Actor model
Thursday 21 October 2010
29. Concurrency oriented
languages
• Erlang (Actors)
• Clojure
• Go (CSP)
• Haskell (several)
• Scala (Actors)
• ...
Thursday 21 October 2010
30. Ideas
• functional programming: side effect
free function calls
- immutable data
• nothing shared (advantage: distributed
= local)
• message passing
Thursday 21 October 2010
33. Rubinius: Actors
• actors in the language: threads with
inbox
• VM actors to communicate between
actors in different VMs
Thursday 21 October 2010
34. Ruby: Revactor
• erlang-like semantics: actor spawn/receive,
filter
• Fibers (so cooperative scheduling)
• Revactor::TCP for non-blocking network
access (1.9.2) (rev eventloop)
Thursday 21 October 2010
35. Go
• Fairly low-level - fit for systems
programming (close to C)
• static typing
• goroutines: parallel execution - sort of
async lightweight thread
• channels !
Thursday 21 October 2010
36. Go
lessReply = make(chan []int)
(...)
lessReq.data = less
lessReq.replyChannel = lessReply
go sort(&lessReq) // asyncstart parallel
execution of sort
listener:
append(<-lessReply, pivot, <-greaterReply)
Thursday 21 October 2010
37. clojure
functional, Lisp-like
concurrency: Software Transactional
Memory System:
• Vars = variable state is thread isolated
• Refs = shared, and mutation within a
transaction (atomic, consistent, isolated) -
Multiversion Concurrency Control -
Thursday 21 October 2010
38. Ruby: STM
• @mentalguy thought experiment
• @technomancy clojure-gem
Thursday 21 October 2010
39. others to handle
concurrency
futures
joins
see http://moonbase.rydia.net/mental/
blog/programming/concurrency-five-
ways.html (@mentalguy)
Thursday 21 October 2010
40. Kernel stuff
Some of these problems have
been solved before ...
Thursday 21 October 2010