concurrency: rubies, plural · 2015. 10. 20. · diminishing returns • communication takes...
TRANSCRIPT
![Page 1: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/1.jpg)
Concurrency: Rubies, Plural
Elise Huard & Eleanor McHugh
RubyConf 2010
![Page 2: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/2.jpg)
manifestoconcurrency matters
![Page 3: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/3.jpg)
multicoreit’s a revolution in mainstream computing
and you want to exploit it in Ruby
![Page 4: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/4.jpg)
MULTIPROCESSOR/MULTICORE
![Page 5: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/5.jpg)
NETWORK ON CHIP(50..96..100 CORES)
![Page 6: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/6.jpg)
diminishing returns
• communication takes finite time
• so doubling processors never doubles a system’s realworld performance
• realtime capacity ~70% theoretical capacity
• or less!!!
• independence = performance
![Page 7: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/7.jpg)
“... 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)
![Page 8: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/8.jpg)
concurrencywhy it really matters
![Page 9: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/9.jpg)
an aide to good design
• decouples independent tasks
• encourages data to flow efficiently
• supports parallel execution
• enhances scalability
• improves program comprehensibility
![Page 10: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/10.jpg)
![Page 11: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/11.jpg)
![Page 12: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/12.jpg)
![Page 13: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/13.jpg)
finding green pasturesadopting concurrency idioms from other languages
![Page 14: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/14.jpg)
victims of choice
Erlang Actors
Go Concurrent Sequential Processes
Clojure Software Transactional Memory
Icon Coexpressions
![Page 15: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/15.jpg)
coroutinessynchronising via transfer of control
![Page 16: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/16.jpg)
icon
• a procedural language
• with a single thread of execution
• generators are decoupled coexpressions
• and goal-directed evaluation
• creates flexible flow-of-control
![Page 17: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/17.jpg)
icon coexpressionsprocedure main()
n := create(seq(1)\10) s := create(squares())c := create(cubes())while write(@n, “\t”, @s, “\t”, @c)
end
procedure seq(start)repeat {
suspend startstart += 1
}end
procedure squares()odds := 3sum := 1repeat {
suspend sum sum +:= oddsodds +:= 2
}end
procedure cubes()odds := 1sum := 1i := create(seq(2))repeat {
suspend sum sum +:= 1 + (odds * 6)odds +:= @i
}end
1 1 1
2 4 8
3 9 27
4 16 64
5 25 125
6 36 216
7 49 343
8 64 512
9 81 729
10 100 1000
![Page 18: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/18.jpg)
ruby fibers
• coexpressions
• bound to a single thread
• scheduled cooperatively
• the basis for enumerators
• library support for full coroutines
![Page 19: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/19.jpg)
ruby coexpressionsdef seq start = 1
Fiber.new do loop do
Fiber.yield start start += 1
endend
end
n = seq()
s = Fiber.new dosum, odds = 1, 3loop do
Fiber.yield sum sum += oddsodds += 2
endend
c = Fiber.new dosum, odds, i = 1, 1, seq(2)loop do
Fiber.yield sum sum += 1 + (odds * 6)odds += i.resume
endend
10.times doputs “#{n.resume}\t#{s.resume}\t#{c.resume}”
end
1 1 1
2 4 8
3 9 27
4 16 64
5 25 125
6 36 216
7 49 343
8 64 512
9 81 729
10 100 1000
![Page 20: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/20.jpg)
ruby coroutinesrequire 'fiber'
def login Fiber.new do |server, name, password| puts "#{server.transfer(Fiber.current)} #{name}" puts "#{server.transfer name} #{password}" puts “login #{server.transfer password}” endend
def authenticate Fiber.new do |client| name = client.transfer "name:" password = client.transfer "password:" if password == "ultrasecret" then client.transfer "succeeded" else client.transfer "failed" end endend
login.transfer authenticate, "jane doe", "ultrasecret"login.transfer authenticate, "john doe", "notsosecret"
name: jane doepassword: ultrasecretlogin succeededname: john doepassword: notsosecretlogin failed
![Page 21: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/21.jpg)
icon revisitedprocedure powers()
repeat {while e := get(queue) do
write(e, “\t”, e^ 2, “\t”, e^ 3)e @&source
}end
procedure process(L)consumer := get(L) every producer := !L do
while put(queue, @producer) doif *queue > 3 then @consumer
@consumer end
global queue
procedure main()queue := []process{ powers(), 1 to 5, seq(6, 1)\5 }
end
1 1 1
2 4 8
3 9 27
4 16 64
5 25 125
6 36 216
7 49 343
8 64 512
9 81 729
10 100 1000
![Page 22: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/22.jpg)
a ruby equivalentrequire 'fiber'
def process consumer, *fibersq = consumer.transfer(Fiber.current)fibers.each do |fiber|
while fiber.alive?q.push(fiber.resume)q = consumer.transfer(q) if q.length > 3
endendconsumer.transfer q
end
powers = Fiber.new do |caller|loop do
caller.transfer([]).each do |e|puts "#{e}\t#{e ** 2}\t#{e ** 3}" rescue nil
endend
end
low_seq = Fiber.new do5.times { |i| Fiber.yield i + 1 }nil
end
high_seq = Fiber.new do(6..10).each { |i| Fiber.yield i }
end
process powers, low_seq, high_seq
1 1 1
2 4 8
3 9 27
4 16 64
5 25 125
6 36 216
7 49 343
8 64 512
9 81 729
10 100 1000
![Page 23: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/23.jpg)
processesthe traditional approach to concurrency
![Page 24: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/24.jpg)
language VM
OS(kernel processes, other processes)
Your program
multicore - multiCPU
![Page 25: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/25.jpg)
processes + threads
Process 2
RAMmemory space
Process 1
thread1
scheduler (OS)
CPU CPU
memory space
thread2 t1 t2 t3
![Page 26: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/26.jpg)
cooperative preemptive
active task has full control scheduler controls task activity
runs until it yields control switches tasks automatically
scheduler activates new task a task can still yield control
blocking I/O blocks the system blocking I/O blocks the task
Classic MacOS MacOS X
schedulers
![Page 27: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/27.jpg)
3 threads, 2 cores
1
2
3
1
1
2
3 1
23
core1 core2 core1 core2
![Page 28: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/28.jpg)
process thread
address space private shared
kernel resources private + shared shared
scheduling kernel varies
communication IPC via kernel in process
control children in process
feature comparison
![Page 29: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/29.jpg)
process creation
• unix spawns
• windows cuts from whole cloth
• ruby wraps this many ways
• but we’re mostly interested in fork
![Page 30: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/30.jpg)
pipes
• creates an I/O channel between processes
• unnamed pipes join two related processes
• posix named pipes
• live in the file system
• have user permissions
![Page 31: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/31.jpg)
def execute &blockchild_input, parent_input = IO.pipepid = fork dochild_input.closeresult = block.callparent_input.write result.to_jsonparent_input.close
endparent_input.closesorted = JSON.parse child_input.readchild_input.closeProcess.waitpid pidreturn sorted
end
forking
![Page 32: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/32.jpg)
context switchingOperating System Benchmark Operation Time (ms)
Linux
spawn new process fork() / exec() 6.000
clone current process fork() 1.000
spawn new thread pthread_create 0.300
switch current process sched_yield() 0.019
switch current thread sched_yield() 0.019
Windows NT
spawn new process spawnl() 12.000
clone current process N/A ---
spawn new thread pthread_create() 0.900
switch current process Sleep(0) 0.010
switch current thread Sleep(0) 0.006
C Benchmarks by Gregory Travis on a P200 MMXhttp://cs.nmu.edu/~randy/Research/Papers/Scheduler/
![Page 33: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/33.jpg)
fork
• exploit OS’s efficiency in spawning processes
• ruby enterprise = patched for COW
• not on Ruby 1.9 (yet)
![Page 34: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/34.jpg)
persistent pipesprocess 1
File.umask 0 MKFIFO = 132syscall MKFIFO, fifo_name, 0666fd = IO.sysopen “server”, File::RDONLYserver = File.new fd, "r"client_name = server.gets.chompputs "#{Time.now}: [#{client_name}]"fd = IO.sysopen client_name, File::WRONLYclient = IO.new fd, "w"message = server.gets.chompclient.puts message.reverseclient.closeserver.closeFile.delete “server”
process 2
File.umask 0 MKFIFO = 132syscall MKFIFO, “client”, 0666fd = IO.sysopen "server", File::WRONLYserver = IO.new fd, "w"server.puts fifo_nameserver.puts "hello world!"server.closefd = IO.sysopen “client”, File::RDONLYclient = IO.new fd, "r"puts client.getsclient.closeFile.delete “client”
![Page 35: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/35.jpg)
shared state hurts
• non-determinism
• atomicity
• fairness/starvation
• race conditions
• locking
• transactional memory
![Page 36: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/36.jpg)
semaphores
• exist independently of processes
• provide blocking access
• allowing processes to be synchronised
• nodes in the file system
• usable from Ruby with syscall
![Page 37: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/37.jpg)
synchronising processesrequire ‘dl’require ‘fcntl’libc = DL::dlopen ‘libc.dylib’ open = libc[‘sem_open’, ‘ISII’]try_wait = libc[‘sem_trywait’, ‘II’]wait = libc[‘sem_wait’, ‘II’]post = libc[‘sem_post’, ‘II’]close = libc[‘sem_close’, ‘II’]
process 1s = open.call(“/tmp/s”, Fcntl::O_CREAT, 1911)[0]wait.call sputs “locked at #{Time.now}”sleep 50puts “posted at #{Time.now}”post.call sclose.call s
process 2s = open.call(“/tmp/s”)t = Time.nowif try_wait.call(s)[0] == 0 then
puts “locked at #{t}”else
puts “busy at #{t}”wait.call sputs “waited #{Time.now - t} seconds”
end
locked at Thu May 28 01:03:23 +0100 2009 busy at Thu May 28 01:03:36 +0100 2009posted at Thu May 28 01:04:13 +0100 2009 waited 47.056508 seconds
![Page 38: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/38.jpg)
complexity
• file locking
• shared memory
• message queues
• transactional data stores
![Page 39: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/39.jpg)
threadsthe popular approach to concurrency
![Page 40: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/40.jpg)
threads under the hood
from http://www.igvita.com/2008/11/13/concurrency-is-a-myth-in-ruby/ @igrigorik
![Page 41: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/41.jpg)
the global lockdown
• compatibility for 1.8 C extensions
• only one thread executes at a time
• scheduled fairly with a timer thread
• 10 μs for Linux
• 10 ms for Windows
![Page 42: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/42.jpg)
the macruby twist
• grand central despatch
• uses an optimal number of threads
• state is shared but not mutable
• object-level queues for atomic mutability
![Page 43: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/43.jpg)
synchronisation
• locks address race conditions
• mutex
• condition variable
• monitor
• deadlocks
• livelocks
![Page 44: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/44.jpg)
RUBY THREADSrequire 'thread'threads = []account = UnsafeAccount.newmutex = Mutex.new10.times dothreads << Thread.new domutex.synchronize doaccount.receive 10
endend
end
threads.each {|t| t.join }
puts account.balance
![Page 45: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/45.jpg)
THREADS + SOCKETSrequire 'socket'require 'thread'require 'mutex_m'
class UDPServerinclude Mutex_m
def start address, port, *options@socket = [email protected] address, [email protected] *optionsevent_loop
end
def [email protected]@socket = nilunlock
end
def serve request["hello", 0]
end
private
def event_looploop do
if sockets = select([@socket]) thensockets[0].each do |s|
spawn_handler send
endend
endend
def spawn_handler sockett = Thread.new(socket) do |s|
message, peer = *s.recvfrom 512reply, status = *serve messageUDPSocket.open.send reply, status, peer[2], peer[1]
endt.join
end
![Page 46: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/46.jpg)
clojure
lisp dialect for the JVM
refs software transactional memory
agents independent, asynchronous change
vars in-thread mutability
check out Tim Bray’s Concur.next series
![Page 47: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/47.jpg)
parallel banking(ns account)
; ref (def transactional-balance (ref 0))
; transfer: within a transaction (defn parallel-transfer [amount] (dosync (alter transactional-balance transfer amount)))
; many threads adding 10 onto account (defn parallel-stm [amount nthreads] (let [threads (for [x (range 0 nthreads)] (Thread. #(parallel-transfer amount)))] (do (doall (map #(.start %) threads)) (doall (map #(.join %) threads)))) @transactional-balance)
![Page 48: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/48.jpg)
ruby can do that toorequire 'clojure'
include Clojure
def parallel_transfer(amount) Ref.dosync do @balance.alter {|b| b + amount } endend
def parallel_stm(amount, nthreads) threads = [] 10.times do threads << Thread.new do parallel_transfer(amount) end end threads.each {|t| t.join } @balance.derefend
@balance = Ref.new(0)puts parallel_stm(10,10)
![Page 49: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/49.jpg)
enumerableseveryday ruby code is often naturally concurrent
![Page 50: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/50.jpg)
map/reduce
• decompose into independent elements
• process each element separately
• use functional code with side-effects
• recombine the elements
• intrinsically suited to parallel execution
![Page 51: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/51.jpg)
a two-phase operationconcurrent sequential
(0..5).to_a.each { |i| puts i }
x = 0(0..5).to_a.each { |i| x = x + i }
(0..5).to_a.map { |i| i ** 2 }
(0..5).to_a.inject { |sum, i| sum + i }
![Page 52: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/52.jpg)
the parallel gemrequire 'brute_force'require 'parallel'
# can be run with :in_processes as wellmapped = Parallel.map((0..3).to_a, :in_threads => 4) do |num| map("english.#{num}") # hash the whole dictionaryend
hashed = "71aa27d3bf313edf99f4302a65e4c042"
puts reduce(hashed, mapped) # returns “zoned”
![Page 53: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/53.jpg)
TECHNIQUES
• event-driven I/O
![Page 54: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/54.jpg)
algebra, actors + eventssynchronising concurrency via communication
![Page 55: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/55.jpg)
process calculi
• mathematical model of interaction
• processes and events
• (a)synchronous message passing
• named channels with atomic semantics
![Page 56: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/56.jpg)
go
• statically-typed compiled systems language
• class-free object-orientation
• garbage collection
• independent lightweight coroutines
• implicit cross-thread scheduling
![Page 57: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/57.jpg)
package mainimport "syscall"
func (c *Clock) Start() {if !c.active {
go func() {c.active = truefor i := int64(0); ; i++ {
select {case status := <- c.Control:
c.active = statusdefault:
if c.active {c.Count <- i
}syscall.Sleep(c.Period)
}}
}()}
}
type Clock struct {Period int64Count chan int64Control chan boolactive bool
}
func main() {c := Clock{1000, make(chan int64), make(chan bool), false}c.Start()
for i := 0; i < 3; i++ {println("pulse value", <-c.Count, "from clock")
}
println("disabling clock")c.Control <- falsesyscall.Sleep(1000000)println("restarting clock")c.Control <- trueprintln("pulse value", <-c.Count, "from clock")
}
produces: pulse value 0 from clock pulse value 1 from clock pulse value 2 from clock disabling clock restarting clock pulse value 106 from clock
a signal generator
![Page 58: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/58.jpg)
RUBY SIGNAL GENERATOR
![Page 59: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/59.jpg)
actor model
• named actors: no shared state
• asynchronous message passing (fire and forget)
![Page 60: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/60.jpg)
erlang
• Actor model: Actors, asynchronous message passing
• actors = “green processes”
• efficient VM (SMP enabled since R12B)
• high reliability
© ericsson 2007
Text
![Page 61: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/61.jpg)
erlang-module(brute_force).-import(plists).-export(run/2).
map(FileName) -> {ok, Binary} = file:read_file(FileName), Lines = string:tokens(erlang:binary_to_list(Binary), "\n"), lists:map(fun(I) -> {erlang:md5(I), I} end, Lines).
reduce(Hashed, Dictionary) -> dict:fetch(Hashed, Dictionary).
run(Hashed, Files) -> Mapped = plists:map(fun(I) -> map(I) end, Files), Values = lists:flatten(Mapped), Dict = dict:from_list(Values), reduce(Hashed, Dict).
![Page 62: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/62.jpg)
rubinius: actors
• actors in the language: threads with inbox
• (VM actors to communicate between actors in different VMs)
![Page 63: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/63.jpg)
rubinius actorsrequire 'quick_sort'require 'actor'
class RbxActorSort
def execute(&block)current = Actor.currentActor.spawn(current) {|current|
current.send(block.call) }Actor.receive
end
end
puts q = QuickSort.new([1,7,3,2,77,23,4,2,90,100,33,2,4], RbxActorSort).sort
![Page 64: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/64.jpg)
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)
![Page 65: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/65.jpg)
ruby: futuresLazy.rb gem (@mentalguy)require 'lazy'require 'lazy/futures'
def fib(n) return n if (0..1).include? n fib(n-1) + fib(n-2) if n > 1end
puts "before first future"future1 = Lazy::Future.new { fib(40) }puts "before second future"future2 = Lazy::Future.new { fib(40) }puts "and now we're waiting for results ... getting futures fulfilled is blocking"
puts future1puts future2
![Page 66: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/66.jpg)
kernel stuff
Some of these problems have been solved before ...
![Page 67: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/67.jpg)
GOLDEN RULES
• beware of shared mutable state
• but: sane ways to handle concurrency
• they are all possible in Ruby
![Page 68: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/68.jpg)
fun
![Page 69: Concurrency: Rubies, Plural · 2015. 10. 20. · diminishing returns • communication takes finite time • so doubling processors never doubles a system’s realworld performance](https://reader033.vdocuments.site/reader033/viewer/2022060822/609b3aa7f0cbe9610c19df93/html5/thumbnails/69.jpg)
http://www.delicious.com/elisehuard/concurrency
http://www.ecst.csuchico.edu/~beej/guide/ipc/
http://wiki.netbsd.se/kqueue_tutorial
http://www.kegel.com/c10k.html
Elise Huard @elise_huard http://jabberwocky.eu
Eleanor McHugh @feyeleanor http://slides.games-with-brains.net
Further Reading