5. How to achieve concurrency
Multiple processes / forking
Threads
Fibers
6. Multiple processes / forking
Most commonly used solution to gain concurrency in Ruby
7. Multiple processes / forking
Most commonly used solution to gain concurrency in Ruby
No shared states between running processes. You need to use DRb, a
message bus like RabbitMQ
8. Multiple processes / forking
Most commonly used solution to gain concurrency in Ruby
No shared states between running processes. You need to use DRb, a
message bus like RabbitMQ
... or some shared data store like MySQL
9. Multiple processes / forking
Most commonly used solution to gain concurrency in Ruby
No shared states between running processes. You need to use DRb, a
message bus like RabbitMQ
... or some shared data store like MySQL
10. Multiple processes / forking
Most commonly used solution to gain concurrency in Ruby
No shared states between running processes. You need to use DRb, a
message bus like RabbitMQ
... or some shared data store like MySQL
Forked processses can read the state of the program before the fork, but
updates wont be shared
11. Multiple processes / forking
LOT of memory used!
5 Rails apps is something like 45MB * 5 = 255MB!
Unix copy-on-write (CoW) comes to help: no need to copy the whole
memory into the forked process, and only the data changed after the fork
will be copied and modified. but...
12. Multiple processes / forking
Ruby Garbage Collector (GC) will write to every object every time
it will run, so the whole process memory will be then copied.
Basically, Ruby loses all the benefits of CoW.
13. Multiple processes / forking
Passenger fixed the copy-on-write issues creating a CoW-
friendly GC, and it will be integrated into Ruby 2.0
14. Multiple processes / forking
Passenger fixed the copy-on-write issues creating a CoW-
friendly GC, and it will be integrated into Ruby 2.0
Rubinius is CoW friendly
15. How to achieve concurrency
Multiple processes / forking
Threads
Fibers
16. Threads
Ruby 1.8 has "green threads". They are scheduled by the VM,
and emulate multithreaded environments even if they are not.
Ruby 1.9 has OS threads.
Preemptive scheduling
17. Threads
Both 1.8 and 1.9 have the Global Interpreter Lock (GIL).
Having GIL means that any time one thread is running Ruby
code, no other thread can be running Ruby code.
Even if you have multiple threads, you can only use at most 1
core of your CPU at a time.
20. Threads
Race conditions, dead locks, synchronizing...
... JRuby manages threads very well, has no GIL and let you
use all your cores.
21. Threads
Race conditions, dead locks, synchronizing...
... JRuby manages threads very well, has no GIL and let you
use all your cores.
Rubinius is working on removing GIL
22. How to achieve concurrency
Multiple processes / forking
Threads
Fibers
23. Fibers
Natively available only in Ruby 1.9
They are like simplified threads, but they aren't
scheduled by the VM but by the programmer
Faster than threads, and use less memory
30. Recap
Forking
GC prevents us to have a proper memory management
Threads
Difficult to manage
Difficult to debug in production
GIL prevents us to have concurrency
31. Recap
Forking
GC prevents us to have a proper memory management
Threads
Difficult to manage
Difficult to debug in production
GIL prevents us to have concurrency
Fibers
32. Recap
Forking
GC prevents us to have a proper memory management
Threads
Difficult to manage
Difficult to debug in production
GIL prevents us to have concurrency
Fibers
Difficult to debug in production
GIL prevents us to have concurrency
36. Reactor Pattern
Application server (AS) receives a request from a browser
AS queues the request in the Reactor
Reactor process the request, passing the control to our App
In order to process the request, our app needs to perform some API
queries over third-party services
37. Reactor Pattern
Application server (AS) receives a request from a browser
AS queues the request in the Reactor
Reactor process the request, passing the control to our App
In order to process the request, our app needs to perform some API
queries over third-party services
...zZzZzzZzZzZ...
38. Reactor Pattern
Application server (AS) receives a request from a browser
AS queues the request in the Reactor
Reactor process the request, passing the control to our App
In order to process the request, our app needs to perform some API
queries over third-party services
...zZzZzzZzZzZ...
39. Reactor Pattern
Our app makes the http request to the third-party service, using an async
library (em-http) and provides a callback to be executed when a reply is
received
Control returns to the Reactor
Reactor pulls the next event from the queue and executes it
40. Reactor Pattern
Earlier HTTP API call returns (or fails!) and the callback is enqueued into the
Reactor
Control returns to the Reactor
Reactor starts executing the callback which processes the results of the API
request, builds a response and sends it to the browser.
Done
41. Blocking I/O
Everything has the advantage of being concurrent
without having to be thread-safe.
It is a "cooperative multitasking"
(while Threads have a “Preemptive scheduling“ approach)
42. EventMachine
Is the Ruby implementation of the Reactor Pattern
::DeferrableChildProcess - Wait for a process to exit
::FileStreamer - Streams a file over a connection
::FileWatch - Monitors a file, get notified when it gets deleted, modified or
moved
::PeriodicTimer - Executes something every interval seconds
43. EventMachine
Is the Ruby implementation of the Reactor Pattern
::Protocols::HttpClient ::Protocols::SmtpServer
::Protocols::Memcache ::Protocols::Socks4
::Protocols::Postgres3 ::Protocols::Stomp
::Protocols::SmtpClient
44. EventMachine
Issues:
Not so very well documented
Difficult to adopt for "syncronous programmers"
Doesn't play well with actual web frameworks
46. EventMachine
EventMachine.run {
page = EventMachine::HttpRequest.new('http://github.com/').get
page.errback { p "GitHub is Down. Everybody run for your life!" }
page.callback {
about = EventMachine::HttpRequest.new('http://github.com/api/v2/json/
repos/show/schacon).get
about.callback { }
about.errback { }
}
}
47. EM-Syncrony
"Collection of convenience classes and primitives to help untangle evented
code, plus a number of patched EM clients to make them Fiber aware."
EventMachine.synchrony do
homepage = EventMachine::HttpRequest.new("http://github.com/").get
apiResponse = EventMachine::HttpRequest.new("'http://github.com/api/v2/
json/repos/show/schacon").get
p "No callbacks! Fetched API: #{apiResponse}"
EventMachine.stop
end