Download presentation
Presentation is loading. Please wait.
1
RubyConf 2012 Artūras 'arturaz' Šlajus
@arturaz_
2
Concurrent vs Parallel
1.8, 1.9 == concurrency Rubinius, JRuby == parallelism
3
Proof? res = Array.new(10, 0).map do |a| threads = (0...10).map do
Thread.new { 1000.times { a += 1 } } end threads.each(&:join) a puts res.inspect
4
Proof! $ rvm use 1.9.2 Using /home/arturas/.rvm/gems/ruby-1.9.2-p318
$ ruby thread.rb [10000, 10000, 10000, 10000, 10000, 10000, , 10000, 10000, 10000] $ rvm use 1.6.7 Using /home/arturas/.rvm/gems/jruby-1.6.7 [9074, 8230, 9571, 9629, 9323, 9371, 9878, 7674, 9239, 8203]
5
Y U NO THREAD?! 1.8.x uses green threads.
1.9.x has kernel level threads, but suffers from GIL. Rubinius & JRuby has kernel level threads and does not have GIL!
6
Rules of multithreading
Don't do it. If you must do it, don't share data across threads. If you must share data across threads, don't share mutable data. If you must share mutable data across threads, synchronize access to that data.
7
What university told us
If you must share mutable data across threads, synchronize access to that data. Mutexes, semaphores, synchronized, yada yada...
8
Solution mutex = Mutex.new res = Array.new(10, 0).map do |a|
threads = (0...10).map do Thread.new { 1000.times { mutex.synchronize { a += 1 } } } end threads.each(&:join) a puts res.inspect
9
PROFIT! $ ruby thread.rb [10000, 10000, 10000, 10000, 10000, 10000, , 10000, 10000, 10000]
10
Problems?
11
Deadlocks Thread 1 Thread 2 R1 R2 1. Req. Locked. 4. Req. Waiting.
12
Livelocks A livelock is similar to a deadlock, except that the states of the processes involved in the livelock constantly change with regard to one another, none progressing. E.g.: two people in the narrow corridor.
13
Complexity Not clear which part of code is executed by which thread.
Need mutexes everywhere! (hint hint - MonitorMixin)
14
Actors to the rescue! If you must do it, don't share data across threads. Actor model does exatcly that. Each actor is an object running in its own thread. Only does 1 method at a time. Other threads cannot access its internal state.
15
Well, sort of... If you must share data across threads, don't share mutable data. Fire and forget. #freeze is your friend. Message-passing helps actors communicate.
16
How? require 'celluloid' class Counter include Celluloid
def = 0; end def += 1; end def end end
17
How? res = Array.new(10) { Counter.new }.map do |a|
threads = (0...10).map do Thread.new { 1000.times { a.inc! } } end threads.each(&:join) a.val puts res.inspect
18
Profit! $ ruby cell_thread.rb
[10000, 10000, 10000, 10000, 10000, 10000, , 10000, 10000, 10000] I, [ T11:43: #29405] INFO -- : Terminating 13 actors... I, [ T11:43: #29405] INFO -- : Shutdown completed cleanly
19
Celluloid features Sync & async calls. Futures.
Linking and supervision. Registry. Timers. Signaling.
20
Real world game server architecture
Main Thread EventMachine IO + JSON Dispatcher Actor Coordinating between IO and App World Director Manages workers Worker Worker Worker Worker Worker Chat Director Worker Callback Manager Doing timed events Application Doing magic
21
Sister projects
22
Evented/Threaded non-blocking IO.
Currently broken :(
23
Provides remoting actors.
Under heavy development.
24
Web server based on celluloid-io.
Toy project.
25
Final words Only one author: Tony Arcieri (@bascule)
Celluloid works good enough, wouldn't bet on other projects.
26
Alternatives At least on JRuby.
Akka provides actor framework for Java/Scala. Netty provides non-blocking IO for Java.
27
Questions?
Similar presentations
© 2024 SlidePlayer.com Inc.
All rights reserved.