SlideShare a Scribd company logo
1 of 71
Download to read offline
Concurrency:
Rubies, Plural
Elise Huard & Eleanor McHugh
RubyConf 2010
Friday 12 November 2010
manifesto
concurrency matters
Friday 12 November 2010
multicore
it’s a revolution in mainstream computing
and you want to exploit it in Ruby
Friday 12 November 2010
MULTIPROCESSOR/MULTICORE
Friday 12 November 2010
NETWORK ON CHIP
(50..96..100 CORES)
Friday 12 November 2010
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
Friday 12 November 2010
“... 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)
Friday 12 November 2010
concurrency
why it really matters
Friday 12 November 2010
an aide to good design
• decouples independent tasks
• encourages data to flow efficiently
• supports parallel execution
• enhances scalability
• improves program comprehensibility
Friday 12 November 2010
Friday 12 November 2010
Friday 12 November 2010
Friday 12 November 2010
finding green pastures
adopting concurrency idioms from other languages
Friday 12 November 2010
victims of choice
Erlang Actors
Go Concurrent Sequential Processes
Clojure Software Transactional Memory
Icon Coexpressions
Friday 12 November 2010
coroutines
synchronising via transfer of control
Friday 12 November 2010
icon
• a procedural language
• with a single thread of execution
• generators are decoupled coexpressions
• and goal-directed evaluation
• creates flexible flow-of-control
Friday 12 November 2010
icon coexpressions
procedure 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 start
start += 1
}
end
procedure squares()
odds := 3
sum := 1
repeat {
suspend sum
sum +:= odds
odds +:= 2
}
end
procedure cubes()
odds := 1
sum := 1
i := 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
Friday 12 November 2010
ruby fibers
• coexpressions
• bound to a single thread
• scheduled cooperatively
• the basis for enumerators
• library support for full coroutines
Friday 12 November 2010
ruby coexpressions
def seq start = 1
Fiber.new do
loop do
Fiber.yield start
start += 1
end
end
end
n = seq()
s = Fiber.new do
sum, odds = 1, 3
loop do
Fiber.yield sum
sum += odds
odds += 2
end
end
c = Fiber.new do
sum, odds, i = 1, 1, seq(2)
loop do
Fiber.yield sum
sum += 1 + (odds * 6)
odds += i.resume
end
end
10.times do
puts “#{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
Friday 12 November 2010
ruby coroutines
require '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}”
end
end
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
end
end
login.transfer authenticate, "jane doe", "ultrasecret"
login.transfer authenticate, "john doe", "notsosecret"
name: jane doe
password: ultrasecret
login succeeded
name: john doe
password: notsosecret
login failed
Friday 12 November 2010
icon revisited
procedure 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) do
if *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
Friday 12 November 2010
a ruby equivalent
require 'fiber'
def process consumer, *fibers
q = consumer.transfer(Fiber.current)
fibers.each do |fiber|
while fiber.alive?
q.push(fiber.resume)
q = consumer.transfer(q) if q.length
> 3
end
end
consumer.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
end
end
end
low_seq = Fiber.new do
5.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
Friday 12 November 2010
processes
the traditional approach to concurrency
Friday 12 November 2010
language VM
OS
(kernel processes, other processes)
Your program
multicore - multiCPU
Friday 12 November 2010
processes + threads
Process 2
RAMmemory space
Process 1
thread1
scheduler (OS)
CPU CPU
memory space
thread2 t1 t2 t3
Friday 12 November 2010
cooperative preemptive
active task has full control scheduler controls task activity
runs until it yields control switches tasks automatically
tasks transfer control directly a task can still yield control
within one thread several threads
schedulers
Friday 12 November 2010
3 threads, 2 cores
1
2
3
1
1
2
3
1
2
3
core1 core2 core1 core2
Friday 12 November 2010
process thread
address space
kernel resources
scheduling
communication
control
private shared
private + shared shared
kernel varies
IPC via kernel in process
children in process
feature comparison
Friday 12 November 2010
process creation
• unix spawns
• windows cuts from whole cloth
• ruby wraps this many ways
• but we’re mostly interested in fork
Friday 12 November 2010
fork
• creates a new process
• in the same state as its parent
• but executing a different code path
• forking is complicated by pthreads
• and ruby’s default garbage collector
Friday 12 November 2010
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
• persist independently of processes
Friday 12 November 2010
def execute &block
child_input, parent_input = IO.pipe
pid = fork do
child_input.close
result = block.call
parent_input.write result.to_json
parent_input.close
end
parent_input.close
sorted = JSON.parse child_input.read
child_input.close
Process.waitpid pid
return sorted
end
forking
Friday 12 November 2010
context switching
Operating System Benchmark Operation Time (ms)
LinuxLinuxLinuxLinuxLinux
Windows NTWindows NTWindows NTWindows NTWindows NT
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
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 MMX
http://cs.nmu.edu/~randy/Research/Papers/Scheduler/
C Benchmarks by Gregory Travis on a P200 MMX
http://cs.nmu.edu/~randy/Research/Papers/Scheduler/
C Benchmarks by Gregory Travis on a P200 MMX
http://cs.nmu.edu/~randy/Research/Papers/Scheduler/
C Benchmarks by Gregory Travis on a P200 MMX
http://cs.nmu.edu/~randy/Research/Papers/Scheduler/
Friday 12 November 2010
shared state hurts
• non-determinism
• atomicity
• fairness/starvation
• race conditions
• locking
• transactional memory
Friday 12 November 2010
semaphores
• exist independently of processes
• provide blocking access
• allowing processes to be synchronised
• nodes in the file system
• usable from Ruby with syscall
Friday 12 November 2010
synchronising processes
require ‘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 1
s = open.call(“/tmp/s”, Fcntl::O_CREAT, 1911)[0]
wait.call s
puts “locked at #{Time.now}”
sleep 50
puts “posted at #{Time.now}”
post.call s
close.call s
process 2
s = open.call(“/tmp/s”)
t = Time.now
if try_wait.call(s)[0] == 0 then
puts “locked at #{t}”
else
puts “busy at #{t}”
wait.call s
puts “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 2009
posted at Thu May 28 01:04:13 +0100 2009 waited 47.056508 seconds
Friday 12 November 2010
complexity
• file locking
• shared memory
• message queues
• transactional data stores
Friday 12 November 2010
threads
the popular approach to concurrency
Friday 12 November 2010
threads under the hood
from http://www.igvita.com/2008/11/13/concurrency-is-a-myth-in-ruby/ @igrigorik
Friday 12 November 2010
the global lock
• 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
Friday 12 November 2010
synchronisation
• thread groups
• locks address race conditions
• mutex + monitor
• condition variable
• deadlocks
• livelocks
Friday 12 November 2010
threads + sockets
require 'socket'
require 'thread'
class ThreadGroup
def all_but_me &block
list. delete_if { |t|
t.name == Thread.current.name
}.each { |t| yield t }
end
def select *names, &block
list.delete_if { |t|
!names.include? t.name
}.each { |t| yield t }
end
end
class Thread
def name= n
raise ArgumentError if key? :name
self[:name] = n
self[:Q] = Queue.new
end
def send message
self[:Q].enq message
end
def bind_transmitter socket
raise ArgumentError if key? :XMIT
self[:socket] = socket
self[:XMIT] = Thread.new(socket, self[:Q]) do |s, q|
loop do
case message = q.deq
when :EXIT: Thread.current.exit
else s.puts message
end
Thread.pass
end
end
end
def disconnect
send "Goodbye #{name}"
send :EXIT
self[:XMIT].join
self[:socket].close
exit
end
end
Friday 12 November 2010
threads + sockets
class ChatServer < TCPServer
def initialize port
@receivers = ThreadGroup.new
@transmitters = ThreadGroup.new
@deceased = ThreadGroup.new
super
end
def register name, socket
@receivers.add(t = Thread.current)
t.name = name
@transmitters.add t.bind_transmitter(socket)
broadcast "#{name} has joined the conversation"
t.send "Welcome #{name}"
end
def connect socket
loop do
begin
socket.print "Please enter your name: "
register socket.readline.chomp).downcase, socket
break
rescue ArgumentError
socket.puts "That name is already in use"
end
end
end
def send message, name = Thread.current.name
@receivers.select(name) { |t| t.send message }
end
def broadcast message
@receivers.all_but_me { |t| t.send message }
end
def listen socket
t = Thread.current
loop do
message = socket.readline.chomp
case message.downcase
when "bye" raise EOFError
when "known" list_known_users
when "quit" raise SystemExit
else broadcast "#{t.name}: #{message}"
end
end
end
def run
while socket = accept
Thread.new(socket) do |socket|
begin
connect socket
listen socket
rescue SystemExit
broadcast "#{Thread.current.name} terminated this conversation"
broadcast :EXIT
send :EXIT
@receivers.all_but_me { |t| t.transmitter.join }
Kernel.exit 0
rescue EOFError
disconnect
end
end
end
end
end
ChatServer.new(3939).run
Friday 12 November 2010
the macruby twist
• grand central dispatch
• uses an optimal number of threads
• state is shared but not mutable
• object-level queues for atomic mutability
Friday 12 November 2010
clojure
lisp dialect for the JVMlisp dialect for the JVM
refs software transactional memory
agents independent, asynchronous change
vars in-thread mutability
check outTim Bray’s Concur.next seriescheck outTim Bray’s Concur.next series
Friday 12 November 2010
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)
Friday 12 November 2010
ruby can do that too
require 'clojure'
include Clojure
def parallel_transfer(amount)
  Ref.dosync do
    @balance.alter {|b| b + amount }
  end
end
def parallel_stm(amount, nthreads)
  threads = []
  10.times do
    threads << Thread.new do
      parallel_transfer(amount)
    end
  end
  threads.each {|t| t.join }
  @balance.deref
end
@balance = Ref.new(0)
puts parallel_stm(10,10)
Friday 12 November 2010
enumerables
everyday ruby code which is naturally concurrent
Friday 12 November 2010
vector processing
• collections are first-class values
• single instruction multiple data
• each datum is processed independently
• successive instructions can be pipelined
• so long as there are no side-effects
Friday 12 November 2010
map/reduce
• decompose into independent elements
• process each element separately
• use functional code without side-effects
• recombine the elements
• intrinsically suited to parallel execution
Friday 12 November 2010
a two-phase operation
concurrent 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 }
Friday 12 November 2010
parallel
require 'brute_force'
require 'parallel'
# can be run with :in_processes as well
mapped = Parallel.map((0..3).to_a, :in_threads => 4) do |num|
  map("english.#{num}") # hash the whole dictionary
end
hashed = "71aa27d3bf313edf99f4302a65e4c042"
puts reduce(hashed, mapped) # returns “zoned”
Friday 12 November 2010
algebra, actors + events
synchronising concurrency via communication
Friday 12 November 2010
process calculi
• mathematical model of interaction
• processes and events
• (a)synchronous message passing
• named channels with atomic semantics
Friday 12 November 2010
go
• statically-typed compiled systems language
• class-free object-orientation
• garbage collection
• independent lightweight coroutines
• implicit cross-thread scheduling
• channels are a first-class datatype
Friday 12 November 2010
package main
import "syscall"
func (c *Clock) Start() {
if !c.active {
go func() {
c.active = true
for i := int64(0); ; i++ {
select {
case status := <- c.Control:
c.active = status
default:
if c.active {
c.Count <- i
}
syscall.Sleep(c.Period)
}
}
}()
}
}
type Clock struct {
Period int64
Count chan int64
Control chan bool
active 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 <- false
syscall.Sleep(1000000)
println("restarting clock")
c.Control <- true
println("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
Friday 12 November 2010
homework
• write a signal generator in ruby
• hints:
• it’s very easy
• look at the thread + socket example
• use atomic queues
• and yes, ruby grok’s csp
Friday 12 November 2010
actor model
•named actors
•fully independent of each other
•asynchronous message passing
•and no shared state
Friday 12 November 2010
erlang
• implements actors with green processes
• efficient SMP-enabledVM
• functional language
• hot code loading
• fault-tolerant
© ericsson 2007
Friday 12 November 2010
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).
Friday 12 November 2010
erlang
pmap(F, L) ->
    S = self(),
    Pids = lists:map(fun(I) -> spawn(fun() -> pmap_f(S, F,
I) end) end, L),
    pmap_gather(Pids).
pmap_gather([H|T]) ->
    receive
        {H, Ret} -> [Ret|pmap_gather(T)]
    end;
pmap_gather([]) ->
    [].
pmap_f(Parent, F, I) ->
    Parent ! {self(), (catch F(I))}.
Friday 12 November 2010
rubinius actors
• implemented as ruby threads
• each thread has an inbox
• cross-VM communication
Friday 12 November 2010
rubinius actors
require 'quick_sort'
require 'actor'
class RbxActorSort
" def execute(&block)
" " current = Actor.current
" " Actor.spawn(current) {|current| current.send
(block.call) }
" " Actor.receive # could have filter
" end
end
puts q = QuickSort.new([1,7,3,2,77,23,4,2,90,100,33,2,4],
RbxActorSort).sort
Friday 12 November 2010
ruby revactor
• erlang-like semantics
• actor spawn/receive
• filter
• uses fibers for cooperative scheduling
• so only works on ruby 1.9
• non-blocking network access in ruby 1.9.2
Friday 12 November 2010
promises + futures
• abstraction for delayed execution
• a promise is calculated in parallel
• a future is calculated on demand
• caller will block when requesting result
• until that result is ready
Friday 12 November 2010
ruby futures
Lazy.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 > 1
end
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 future1
puts future2
Friday 12 November 2010
we didn’t cover
• tuple spaces (Rinda)
• event-driven IO
• petri nets
• ...
Friday 12 November 2010
reinventing?
some of these problems have
been solved before ...
Friday 12 November 2010
to surmise
• beware of shared mutable state
• but: sane ways to handle concurrency
• they are all possible in Ruby
Friday 12 November 2010
fun!
Friday 12 November 2010
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
Friday 12 November 2010

More Related Content

What's hot

Kotlin from-scratch 3 - coroutines
Kotlin from-scratch 3 - coroutinesKotlin from-scratch 3 - coroutines
Kotlin from-scratch 3 - coroutinesFranco Lombardo
 
Non blocking io with netty
Non blocking io with nettyNon blocking io with netty
Non blocking io with nettyZauber
 
Deep dumpster diving 2010
Deep dumpster diving 2010Deep dumpster diving 2010
Deep dumpster diving 2010RonnBlack
 
Scheduling in Linux and Web Servers
Scheduling in Linux and Web ServersScheduling in Linux and Web Servers
Scheduling in Linux and Web ServersDavid Evans
 
Cassandra summit 2013 - DataStax Java Driver Unleashed!
Cassandra summit 2013 - DataStax Java Driver Unleashed!Cassandra summit 2013 - DataStax Java Driver Unleashed!
Cassandra summit 2013 - DataStax Java Driver Unleashed!Michaël Figuière
 
CloudClustering: Toward a scalable machine learning toolkit for Windows Azure
CloudClustering: Toward a scalable machine learning toolkit for Windows AzureCloudClustering: Toward a scalable machine learning toolkit for Windows Azure
CloudClustering: Toward a scalable machine learning toolkit for Windows AzureAnkur Dave
 
Virtual nodes: Operational Aspirin
Virtual nodes: Operational AspirinVirtual nodes: Operational Aspirin
Virtual nodes: Operational AspirinAcunu
 
CS6401 Operating systems - Solved Examples
CS6401 Operating systems - Solved ExamplesCS6401 Operating systems - Solved Examples
CS6401 Operating systems - Solved Examplesramyaranjith
 
The Ring programming language version 1.9 book - Part 48 of 210
The Ring programming language version 1.9 book - Part 48 of 210The Ring programming language version 1.9 book - Part 48 of 210
The Ring programming language version 1.9 book - Part 48 of 210Mahmoud Samir Fayed
 
Writing Domain-Specific Languages for BeepBeep
Writing Domain-Specific Languages for BeepBeepWriting Domain-Specific Languages for BeepBeep
Writing Domain-Specific Languages for BeepBeepSylvain Hallé
 
Techfest 2013 No RESTKit for the Weary
Techfest 2013 No RESTKit for the WearyTechfest 2013 No RESTKit for the Weary
Techfest 2013 No RESTKit for the WearyMatt Galloway
 
MessagePack - An efficient binary serialization format
MessagePack - An efficient binary serialization formatMessagePack - An efficient binary serialization format
MessagePack - An efficient binary serialization formatLarry Nung
 
Counter Wars (JEEConf 2016)
Counter Wars (JEEConf 2016)Counter Wars (JEEConf 2016)
Counter Wars (JEEConf 2016)Alexey Fyodorov
 
Node.js - A practical introduction (v2)
Node.js  - A practical introduction (v2)Node.js  - A practical introduction (v2)
Node.js - A practical introduction (v2)Felix Geisendörfer
 
Introduce leo-redundant-manager
Introduce leo-redundant-managerIntroduce leo-redundant-manager
Introduce leo-redundant-managerParas Patel
 
Real-time streams and logs with Storm and Kafka
Real-time streams and logs with Storm and KafkaReal-time streams and logs with Storm and Kafka
Real-time streams and logs with Storm and KafkaAndrew Montalenti
 

What's hot (20)

Kotlin from-scratch 3 - coroutines
Kotlin from-scratch 3 - coroutinesKotlin from-scratch 3 - coroutines
Kotlin from-scratch 3 - coroutines
 
Non blocking io with netty
Non blocking io with nettyNon blocking io with netty
Non blocking io with netty
 
Node.js in production
Node.js in productionNode.js in production
Node.js in production
 
Deep dumpster diving 2010
Deep dumpster diving 2010Deep dumpster diving 2010
Deep dumpster diving 2010
 
Scheduling in Linux and Web Servers
Scheduling in Linux and Web ServersScheduling in Linux and Web Servers
Scheduling in Linux and Web Servers
 
Barcamp presentation
Barcamp presentationBarcamp presentation
Barcamp presentation
 
Cassandra summit 2013 - DataStax Java Driver Unleashed!
Cassandra summit 2013 - DataStax Java Driver Unleashed!Cassandra summit 2013 - DataStax Java Driver Unleashed!
Cassandra summit 2013 - DataStax Java Driver Unleashed!
 
CloudClustering: Toward a scalable machine learning toolkit for Windows Azure
CloudClustering: Toward a scalable machine learning toolkit for Windows AzureCloudClustering: Toward a scalable machine learning toolkit for Windows Azure
CloudClustering: Toward a scalable machine learning toolkit for Windows Azure
 
Virtual nodes: Operational Aspirin
Virtual nodes: Operational AspirinVirtual nodes: Operational Aspirin
Virtual nodes: Operational Aspirin
 
CS6401 Operating systems - Solved Examples
CS6401 Operating systems - Solved ExamplesCS6401 Operating systems - Solved Examples
CS6401 Operating systems - Solved Examples
 
The Ring programming language version 1.9 book - Part 48 of 210
The Ring programming language version 1.9 book - Part 48 of 210The Ring programming language version 1.9 book - Part 48 of 210
The Ring programming language version 1.9 book - Part 48 of 210
 
Writing Domain-Specific Languages for BeepBeep
Writing Domain-Specific Languages for BeepBeepWriting Domain-Specific Languages for BeepBeep
Writing Domain-Specific Languages for BeepBeep
 
Techfest 2013 No RESTKit for the Weary
Techfest 2013 No RESTKit for the WearyTechfest 2013 No RESTKit for the Weary
Techfest 2013 No RESTKit for the Weary
 
MessagePack - An efficient binary serialization format
MessagePack - An efficient binary serialization formatMessagePack - An efficient binary serialization format
MessagePack - An efficient binary serialization format
 
Session 1 introduction to ns2
Session 1   introduction to ns2Session 1   introduction to ns2
Session 1 introduction to ns2
 
Counter Wars (JEEConf 2016)
Counter Wars (JEEConf 2016)Counter Wars (JEEConf 2016)
Counter Wars (JEEConf 2016)
 
Node.js - A practical introduction (v2)
Node.js  - A practical introduction (v2)Node.js  - A practical introduction (v2)
Node.js - A practical introduction (v2)
 
Introduce leo-redundant-manager
Introduce leo-redundant-managerIntroduce leo-redundant-manager
Introduce leo-redundant-manager
 
Node.js - As a networking tool
Node.js - As a networking toolNode.js - As a networking tool
Node.js - As a networking tool
 
Real-time streams and logs with Storm and Kafka
Real-time streams and logs with Storm and KafkaReal-time streams and logs with Storm and Kafka
Real-time streams and logs with Storm and Kafka
 

Similar to Concurrency: Rubies, plural

Concurrency
ConcurrencyConcurrency
Concurrencyehuard
 
[Greach 17] make concurrency groovy again
[Greach 17] make concurrency groovy again[Greach 17] make concurrency groovy again
[Greach 17] make concurrency groovy againAlonso Torres
 
Braxton McKee, Founder & CEO, Ufora at MLconf SF - 11/13/15
Braxton McKee, Founder & CEO, Ufora at MLconf SF - 11/13/15Braxton McKee, Founder & CEO, Ufora at MLconf SF - 11/13/15
Braxton McKee, Founder & CEO, Ufora at MLconf SF - 11/13/15MLconf
 
The Ruby Guide to *nix Plumbing: on the quest for efficiency with Ruby [M|K]RI
The Ruby Guide to *nix Plumbing: on the quest for efficiency with Ruby [M|K]RIThe Ruby Guide to *nix Plumbing: on the quest for efficiency with Ruby [M|K]RI
The Ruby Guide to *nix Plumbing: on the quest for efficiency with Ruby [M|K]RIEleanor McHugh
 
Concurrent programming with Celluloid (MWRC 2012)
Concurrent programming with Celluloid (MWRC 2012)Concurrent programming with Celluloid (MWRC 2012)
Concurrent programming with Celluloid (MWRC 2012)tarcieri
 
Building Distributed Systems
Building Distributed SystemsBuilding Distributed Systems
Building Distributed SystemsPivorak MeetUp
 
Puppetcamp Melbourne - puppetdb
Puppetcamp Melbourne - puppetdbPuppetcamp Melbourne - puppetdb
Puppetcamp Melbourne - puppetdbm_richardson
 
Puppet Camp Melbourne 2014: Node Collaboration with PuppetDB
Puppet Camp Melbourne 2014: Node Collaboration with PuppetDBPuppet Camp Melbourne 2014: Node Collaboration with PuppetDB
Puppet Camp Melbourne 2014: Node Collaboration with PuppetDBPuppet
 
Exploiting Concurrency with Dynamic Languages
Exploiting Concurrency with Dynamic LanguagesExploiting Concurrency with Dynamic Languages
Exploiting Concurrency with Dynamic LanguagesTobias Lindaaker
 
node.js, javascript and the future
node.js, javascript and the futurenode.js, javascript and the future
node.js, javascript and the futureJeff Miccolis
 
Distributed Data Structures
Distributed Data StructuresDistributed Data Structures
Distributed Data StructuresPDX Web & Design
 
Exploring Clojurescript
Exploring ClojurescriptExploring Clojurescript
Exploring ClojurescriptLuke Donnet
 
Rubinius @ RubyAndRails2010
Rubinius @ RubyAndRails2010Rubinius @ RubyAndRails2010
Rubinius @ RubyAndRails2010Dirkjan Bussink
 
More Data, More Problems: Evolving big data machine learning pipelines with S...
More Data, More Problems: Evolving big data machine learning pipelines with S...More Data, More Problems: Evolving big data machine learning pipelines with S...
More Data, More Problems: Evolving big data machine learning pipelines with S...Alex Sadovsky
 
Leveraging open source tools to gain insight into OpenStack Swift
Leveraging open source tools to gain insight into OpenStack SwiftLeveraging open source tools to gain insight into OpenStack Swift
Leveraging open source tools to gain insight into OpenStack SwiftDmitry Sotnikov
 
From Java to Parellel Clojure - Clojure South 2019
From Java to Parellel Clojure - Clojure South 2019From Java to Parellel Clojure - Clojure South 2019
From Java to Parellel Clojure - Clojure South 2019Leonardo Borges
 

Similar to Concurrency: Rubies, plural (20)

Concurrency
ConcurrencyConcurrency
Concurrency
 
[Greach 17] make concurrency groovy again
[Greach 17] make concurrency groovy again[Greach 17] make concurrency groovy again
[Greach 17] make concurrency groovy again
 
Braxton McKee, Founder & CEO, Ufora at MLconf SF - 11/13/15
Braxton McKee, Founder & CEO, Ufora at MLconf SF - 11/13/15Braxton McKee, Founder & CEO, Ufora at MLconf SF - 11/13/15
Braxton McKee, Founder & CEO, Ufora at MLconf SF - 11/13/15
 
The Ruby Guide to *nix Plumbing: on the quest for efficiency with Ruby [M|K]RI
The Ruby Guide to *nix Plumbing: on the quest for efficiency with Ruby [M|K]RIThe Ruby Guide to *nix Plumbing: on the quest for efficiency with Ruby [M|K]RI
The Ruby Guide to *nix Plumbing: on the quest for efficiency with Ruby [M|K]RI
 
Intro to Multitasking
Intro to MultitaskingIntro to Multitasking
Intro to Multitasking
 
Current State of Coroutines
Current State of CoroutinesCurrent State of Coroutines
Current State of Coroutines
 
ActiveRecord 2.3
ActiveRecord 2.3ActiveRecord 2.3
ActiveRecord 2.3
 
Concurrent programming with Celluloid (MWRC 2012)
Concurrent programming with Celluloid (MWRC 2012)Concurrent programming with Celluloid (MWRC 2012)
Concurrent programming with Celluloid (MWRC 2012)
 
Building Distributed Systems
Building Distributed SystemsBuilding Distributed Systems
Building Distributed Systems
 
Puppetcamp Melbourne - puppetdb
Puppetcamp Melbourne - puppetdbPuppetcamp Melbourne - puppetdb
Puppetcamp Melbourne - puppetdb
 
Puppet Camp Melbourne 2014: Node Collaboration with PuppetDB
Puppet Camp Melbourne 2014: Node Collaboration with PuppetDBPuppet Camp Melbourne 2014: Node Collaboration with PuppetDB
Puppet Camp Melbourne 2014: Node Collaboration with PuppetDB
 
Devoxx 17 - Swift server-side
Devoxx 17 - Swift server-sideDevoxx 17 - Swift server-side
Devoxx 17 - Swift server-side
 
Exploiting Concurrency with Dynamic Languages
Exploiting Concurrency with Dynamic LanguagesExploiting Concurrency with Dynamic Languages
Exploiting Concurrency with Dynamic Languages
 
node.js, javascript and the future
node.js, javascript and the futurenode.js, javascript and the future
node.js, javascript and the future
 
Distributed Data Structures
Distributed Data StructuresDistributed Data Structures
Distributed Data Structures
 
Exploring Clojurescript
Exploring ClojurescriptExploring Clojurescript
Exploring Clojurescript
 
Rubinius @ RubyAndRails2010
Rubinius @ RubyAndRails2010Rubinius @ RubyAndRails2010
Rubinius @ RubyAndRails2010
 
More Data, More Problems: Evolving big data machine learning pipelines with S...
More Data, More Problems: Evolving big data machine learning pipelines with S...More Data, More Problems: Evolving big data machine learning pipelines with S...
More Data, More Problems: Evolving big data machine learning pipelines with S...
 
Leveraging open source tools to gain insight into OpenStack Swift
Leveraging open source tools to gain insight into OpenStack SwiftLeveraging open source tools to gain insight into OpenStack Swift
Leveraging open source tools to gain insight into OpenStack Swift
 
From Java to Parellel Clojure - Clojure South 2019
From Java to Parellel Clojure - Clojure South 2019From Java to Parellel Clojure - Clojure South 2019
From Java to Parellel Clojure - Clojure South 2019
 

More from ehuard

Euroclojure 2017
Euroclojure 2017Euroclojure 2017
Euroclojure 2017ehuard
 
Ruby goes to Hollywood
Ruby goes to HollywoodRuby goes to Hollywood
Ruby goes to Hollywoodehuard
 
Ruby hollywood nordic
Ruby hollywood nordicRuby hollywood nordic
Ruby hollywood nordicehuard
 
Ruby goes to hollywood
Ruby goes to hollywoodRuby goes to hollywood
Ruby goes to hollywoodehuard
 
Ruby hollywood
Ruby hollywoodRuby hollywood
Ruby hollywoodehuard
 
Concurrency
ConcurrencyConcurrency
Concurrencyehuard
 
12 hours to rate a rails application
12 hours to rate a rails application12 hours to rate a rails application
12 hours to rate a rails applicationehuard
 
how to rate a Rails application
how to rate a Rails applicationhow to rate a Rails application
how to rate a Rails applicationehuard
 
12 Hours To Rate A Rails Application
12 Hours To Rate A Rails Application12 Hours To Rate A Rails Application
12 Hours To Rate A Rails Applicationehuard
 
Barcamp Ghent2009
Barcamp Ghent2009Barcamp Ghent2009
Barcamp Ghent2009ehuard
 
Tokyo Cabinet
Tokyo CabinetTokyo Cabinet
Tokyo Cabinetehuard
 
The real-time web
The real-time webThe real-time web
The real-time webehuard
 
Rails and the internet of things
Rails and the internet of thingsRails and the internet of things
Rails and the internet of thingsehuard
 

More from ehuard (14)

Euroclojure 2017
Euroclojure 2017Euroclojure 2017
Euroclojure 2017
 
Ruby goes to Hollywood
Ruby goes to HollywoodRuby goes to Hollywood
Ruby goes to Hollywood
 
Ruby hollywood nordic
Ruby hollywood nordicRuby hollywood nordic
Ruby hollywood nordic
 
Ruby goes to hollywood
Ruby goes to hollywoodRuby goes to hollywood
Ruby goes to hollywood
 
Ruby hollywood
Ruby hollywoodRuby hollywood
Ruby hollywood
 
Concurrency
ConcurrencyConcurrency
Concurrency
 
12 hours to rate a rails application
12 hours to rate a rails application12 hours to rate a rails application
12 hours to rate a rails application
 
how to rate a Rails application
how to rate a Rails applicationhow to rate a Rails application
how to rate a Rails application
 
12 Hours To Rate A Rails Application
12 Hours To Rate A Rails Application12 Hours To Rate A Rails Application
12 Hours To Rate A Rails Application
 
Barcamp Ghent2009
Barcamp Ghent2009Barcamp Ghent2009
Barcamp Ghent2009
 
Tokyo Cabinet
Tokyo CabinetTokyo Cabinet
Tokyo Cabinet
 
The real-time web
The real-time webThe real-time web
The real-time web
 
Rails and the internet of things
Rails and the internet of thingsRails and the internet of things
Rails and the internet of things
 
Oauth
OauthOauth
Oauth
 

Recently uploaded

Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupFlorian Wilhelm
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubKalema Edgar
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Commit University
 
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024BookNet Canada
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024The Digital Insurer
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024Neo4j
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDGMarianaLemus7
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Enterprise Knowledge
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationSlibray Presentation
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii SoldatenkoFwdays
 

Recently uploaded (20)

Streamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project SetupStreamlining Python Development: A Guide to a Modern Project Setup
Streamlining Python Development: A Guide to a Modern Project Setup
 
Unleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding ClubUnleash Your Potential - Namagunga Girls Coding Club
Unleash Your Potential - Namagunga Girls Coding Club
 
Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!Nell’iperspazio con Rocket: il Framework Web di Rust!
Nell’iperspazio con Rocket: il Framework Web di Rust!
 
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024Build your next Gen AI Breakthrough - April 2024
Build your next Gen AI Breakthrough - April 2024
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
APIForce Zurich 5 April Automation LPDG
APIForce Zurich 5 April  Automation LPDGAPIForce Zurich 5 April  Automation LPDG
APIForce Zurich 5 April Automation LPDG
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024Designing IA for AI - Information Architecture Conference 2024
Designing IA for AI - Information Architecture Conference 2024
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
Connect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck PresentationConnect Wave/ connectwave Pitch Deck Presentation
Connect Wave/ connectwave Pitch Deck Presentation
 
"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko"Debugging python applications inside k8s environment", Andrii Soldatenko
"Debugging python applications inside k8s environment", Andrii Soldatenko
 

Concurrency: Rubies, plural

  • 1. Concurrency: Rubies, Plural Elise Huard & Eleanor McHugh RubyConf 2010 Friday 12 November 2010
  • 3. multicore it’s a revolution in mainstream computing and you want to exploit it in Ruby Friday 12 November 2010
  • 5. NETWORK ON CHIP (50..96..100 CORES) Friday 12 November 2010
  • 6. 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 Friday 12 November 2010
  • 7. “... 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) Friday 12 November 2010
  • 8. concurrency why it really matters Friday 12 November 2010
  • 9. an aide to good design • decouples independent tasks • encourages data to flow efficiently • supports parallel execution • enhances scalability • improves program comprehensibility Friday 12 November 2010
  • 13. finding green pastures adopting concurrency idioms from other languages Friday 12 November 2010
  • 14. victims of choice Erlang Actors Go Concurrent Sequential Processes Clojure Software Transactional Memory Icon Coexpressions Friday 12 November 2010
  • 15. coroutines synchronising via transfer of control Friday 12 November 2010
  • 16. icon • a procedural language • with a single thread of execution • generators are decoupled coexpressions • and goal-directed evaluation • creates flexible flow-of-control Friday 12 November 2010
  • 17. icon coexpressions procedure 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 start start += 1 } end procedure squares() odds := 3 sum := 1 repeat { suspend sum sum +:= odds odds +:= 2 } end procedure cubes() odds := 1 sum := 1 i := 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 Friday 12 November 2010
  • 18. ruby fibers • coexpressions • bound to a single thread • scheduled cooperatively • the basis for enumerators • library support for full coroutines Friday 12 November 2010
  • 19. ruby coexpressions def seq start = 1 Fiber.new do loop do Fiber.yield start start += 1 end end end n = seq() s = Fiber.new do sum, odds = 1, 3 loop do Fiber.yield sum sum += odds odds += 2 end end c = Fiber.new do sum, odds, i = 1, 1, seq(2) loop do Fiber.yield sum sum += 1 + (odds * 6) odds += i.resume end end 10.times do puts “#{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 Friday 12 November 2010
  • 20. ruby coroutines require '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}” end end 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 end end login.transfer authenticate, "jane doe", "ultrasecret" login.transfer authenticate, "john doe", "notsosecret" name: jane doe password: ultrasecret login succeeded name: john doe password: notsosecret login failed Friday 12 November 2010
  • 21. icon revisited procedure 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) do if *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 Friday 12 November 2010
  • 22. a ruby equivalent require 'fiber' def process consumer, *fibers q = consumer.transfer(Fiber.current) fibers.each do |fiber| while fiber.alive? q.push(fiber.resume) q = consumer.transfer(q) if q.length > 3 end end consumer.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 end end end low_seq = Fiber.new do 5.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 Friday 12 November 2010
  • 23. processes the traditional approach to concurrency Friday 12 November 2010
  • 24. language VM OS (kernel processes, other processes) Your program multicore - multiCPU Friday 12 November 2010
  • 25. processes + threads Process 2 RAMmemory space Process 1 thread1 scheduler (OS) CPU CPU memory space thread2 t1 t2 t3 Friday 12 November 2010
  • 26. cooperative preemptive active task has full control scheduler controls task activity runs until it yields control switches tasks automatically tasks transfer control directly a task can still yield control within one thread several threads schedulers Friday 12 November 2010
  • 27. 3 threads, 2 cores 1 2 3 1 1 2 3 1 2 3 core1 core2 core1 core2 Friday 12 November 2010
  • 28. process thread address space kernel resources scheduling communication control private shared private + shared shared kernel varies IPC via kernel in process children in process feature comparison Friday 12 November 2010
  • 29. process creation • unix spawns • windows cuts from whole cloth • ruby wraps this many ways • but we’re mostly interested in fork Friday 12 November 2010
  • 30. fork • creates a new process • in the same state as its parent • but executing a different code path • forking is complicated by pthreads • and ruby’s default garbage collector Friday 12 November 2010
  • 31. 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 • persist independently of processes Friday 12 November 2010
  • 32. def execute &block child_input, parent_input = IO.pipe pid = fork do child_input.close result = block.call parent_input.write result.to_json parent_input.close end parent_input.close sorted = JSON.parse child_input.read child_input.close Process.waitpid pid return sorted end forking Friday 12 November 2010
  • 33. context switching Operating System Benchmark Operation Time (ms) LinuxLinuxLinuxLinuxLinux Windows NTWindows NTWindows NTWindows NTWindows NT 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 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 MMX http://cs.nmu.edu/~randy/Research/Papers/Scheduler/ C Benchmarks by Gregory Travis on a P200 MMX http://cs.nmu.edu/~randy/Research/Papers/Scheduler/ C Benchmarks by Gregory Travis on a P200 MMX http://cs.nmu.edu/~randy/Research/Papers/Scheduler/ C Benchmarks by Gregory Travis on a P200 MMX http://cs.nmu.edu/~randy/Research/Papers/Scheduler/ Friday 12 November 2010
  • 34. shared state hurts • non-determinism • atomicity • fairness/starvation • race conditions • locking • transactional memory Friday 12 November 2010
  • 35. semaphores • exist independently of processes • provide blocking access • allowing processes to be synchronised • nodes in the file system • usable from Ruby with syscall Friday 12 November 2010
  • 36. synchronising processes require ‘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 1 s = open.call(“/tmp/s”, Fcntl::O_CREAT, 1911)[0] wait.call s puts “locked at #{Time.now}” sleep 50 puts “posted at #{Time.now}” post.call s close.call s process 2 s = open.call(“/tmp/s”) t = Time.now if try_wait.call(s)[0] == 0 then puts “locked at #{t}” else puts “busy at #{t}” wait.call s puts “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 2009 posted at Thu May 28 01:04:13 +0100 2009 waited 47.056508 seconds Friday 12 November 2010
  • 37. complexity • file locking • shared memory • message queues • transactional data stores Friday 12 November 2010
  • 38. threads the popular approach to concurrency Friday 12 November 2010
  • 39. threads under the hood from http://www.igvita.com/2008/11/13/concurrency-is-a-myth-in-ruby/ @igrigorik Friday 12 November 2010
  • 40. the global lock • 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 Friday 12 November 2010
  • 41. synchronisation • thread groups • locks address race conditions • mutex + monitor • condition variable • deadlocks • livelocks Friday 12 November 2010
  • 42. threads + sockets require 'socket' require 'thread' class ThreadGroup def all_but_me &block list. delete_if { |t| t.name == Thread.current.name }.each { |t| yield t } end def select *names, &block list.delete_if { |t| !names.include? t.name }.each { |t| yield t } end end class Thread def name= n raise ArgumentError if key? :name self[:name] = n self[:Q] = Queue.new end def send message self[:Q].enq message end def bind_transmitter socket raise ArgumentError if key? :XMIT self[:socket] = socket self[:XMIT] = Thread.new(socket, self[:Q]) do |s, q| loop do case message = q.deq when :EXIT: Thread.current.exit else s.puts message end Thread.pass end end end def disconnect send "Goodbye #{name}" send :EXIT self[:XMIT].join self[:socket].close exit end end Friday 12 November 2010
  • 43. threads + sockets class ChatServer < TCPServer def initialize port @receivers = ThreadGroup.new @transmitters = ThreadGroup.new @deceased = ThreadGroup.new super end def register name, socket @receivers.add(t = Thread.current) t.name = name @transmitters.add t.bind_transmitter(socket) broadcast "#{name} has joined the conversation" t.send "Welcome #{name}" end def connect socket loop do begin socket.print "Please enter your name: " register socket.readline.chomp).downcase, socket break rescue ArgumentError socket.puts "That name is already in use" end end end def send message, name = Thread.current.name @receivers.select(name) { |t| t.send message } end def broadcast message @receivers.all_but_me { |t| t.send message } end def listen socket t = Thread.current loop do message = socket.readline.chomp case message.downcase when "bye" raise EOFError when "known" list_known_users when "quit" raise SystemExit else broadcast "#{t.name}: #{message}" end end end def run while socket = accept Thread.new(socket) do |socket| begin connect socket listen socket rescue SystemExit broadcast "#{Thread.current.name} terminated this conversation" broadcast :EXIT send :EXIT @receivers.all_but_me { |t| t.transmitter.join } Kernel.exit 0 rescue EOFError disconnect end end end end end ChatServer.new(3939).run Friday 12 November 2010
  • 44. the macruby twist • grand central dispatch • uses an optimal number of threads • state is shared but not mutable • object-level queues for atomic mutability Friday 12 November 2010
  • 45. clojure lisp dialect for the JVMlisp dialect for the JVM refs software transactional memory agents independent, asynchronous change vars in-thread mutability check outTim Bray’s Concur.next seriescheck outTim Bray’s Concur.next series Friday 12 November 2010
  • 46. 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) Friday 12 November 2010
  • 47. ruby can do that too require 'clojure' include Clojure def parallel_transfer(amount)   Ref.dosync do     @balance.alter {|b| b + amount }   end end def parallel_stm(amount, nthreads)   threads = []   10.times do     threads << Thread.new do       parallel_transfer(amount)     end   end   threads.each {|t| t.join }   @balance.deref end @balance = Ref.new(0) puts parallel_stm(10,10) Friday 12 November 2010
  • 48. enumerables everyday ruby code which is naturally concurrent Friday 12 November 2010
  • 49. vector processing • collections are first-class values • single instruction multiple data • each datum is processed independently • successive instructions can be pipelined • so long as there are no side-effects Friday 12 November 2010
  • 50. map/reduce • decompose into independent elements • process each element separately • use functional code without side-effects • recombine the elements • intrinsically suited to parallel execution Friday 12 November 2010
  • 51. a two-phase operation concurrent 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 } Friday 12 November 2010
  • 52. parallel require 'brute_force' require 'parallel' # can be run with :in_processes as well mapped = Parallel.map((0..3).to_a, :in_threads => 4) do |num|   map("english.#{num}") # hash the whole dictionary end hashed = "71aa27d3bf313edf99f4302a65e4c042" puts reduce(hashed, mapped) # returns “zoned” Friday 12 November 2010
  • 53. algebra, actors + events synchronising concurrency via communication Friday 12 November 2010
  • 54. process calculi • mathematical model of interaction • processes and events • (a)synchronous message passing • named channels with atomic semantics Friday 12 November 2010
  • 55. go • statically-typed compiled systems language • class-free object-orientation • garbage collection • independent lightweight coroutines • implicit cross-thread scheduling • channels are a first-class datatype Friday 12 November 2010
  • 56. package main import "syscall" func (c *Clock) Start() { if !c.active { go func() { c.active = true for i := int64(0); ; i++ { select { case status := <- c.Control: c.active = status default: if c.active { c.Count <- i } syscall.Sleep(c.Period) } } }() } } type Clock struct { Period int64 Count chan int64 Control chan bool active 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 <- false syscall.Sleep(1000000) println("restarting clock") c.Control <- true println("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 Friday 12 November 2010
  • 57. homework • write a signal generator in ruby • hints: • it’s very easy • look at the thread + socket example • use atomic queues • and yes, ruby grok’s csp Friday 12 November 2010
  • 58. actor model •named actors •fully independent of each other •asynchronous message passing •and no shared state Friday 12 November 2010
  • 59. erlang • implements actors with green processes • efficient SMP-enabledVM • functional language • hot code loading • fault-tolerant © ericsson 2007 Friday 12 November 2010
  • 60. 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). Friday 12 November 2010
  • 61. erlang pmap(F, L) ->     S = self(),     Pids = lists:map(fun(I) -> spawn(fun() -> pmap_f(S, F, I) end) end, L),     pmap_gather(Pids). pmap_gather([H|T]) ->     receive         {H, Ret} -> [Ret|pmap_gather(T)]     end; pmap_gather([]) ->     []. pmap_f(Parent, F, I) ->     Parent ! {self(), (catch F(I))}. Friday 12 November 2010
  • 62. rubinius actors • implemented as ruby threads • each thread has an inbox • cross-VM communication Friday 12 November 2010
  • 63. rubinius actors require 'quick_sort' require 'actor' class RbxActorSort " def execute(&block) " " current = Actor.current " " Actor.spawn(current) {|current| current.send (block.call) } " " Actor.receive # could have filter " end end puts q = QuickSort.new([1,7,3,2,77,23,4,2,90,100,33,2,4], RbxActorSort).sort Friday 12 November 2010
  • 64. ruby revactor • erlang-like semantics • actor spawn/receive • filter • uses fibers for cooperative scheduling • so only works on ruby 1.9 • non-blocking network access in ruby 1.9.2 Friday 12 November 2010
  • 65. promises + futures • abstraction for delayed execution • a promise is calculated in parallel • a future is calculated on demand • caller will block when requesting result • until that result is ready Friday 12 November 2010
  • 66. ruby futures Lazy.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 > 1 end 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 future1 puts future2 Friday 12 November 2010
  • 67. we didn’t cover • tuple spaces (Rinda) • event-driven IO • petri nets • ... Friday 12 November 2010
  • 68. reinventing? some of these problems have been solved before ... Friday 12 November 2010
  • 69. to surmise • beware of shared mutable state • but: sane ways to handle concurrency • they are all possible in Ruby Friday 12 November 2010
  • 71. 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 Friday 12 November 2010