Slideshare uses cookies to improve functionality and performance, and to provide you with relevant advertising. If you continue browsing the site, you agree to the use of cookies on this website. See our User Agreement and Privacy Policy.

Slideshare uses cookies to improve functionality and performance, and to provide you with relevant advertising. If you continue browsing the site, you agree to the use of cookies on this website. See our Privacy Policy and User Agreement for details.

Everything You Know About The GIL Is Wrong

When a Rubyist hears "concurrency" they usually Google Elixir, Go, or even Node.js. Turns out, Ruby can be great for concurrency! The Global Interpreter Lock (GIL) does NOT prevent Ruby programs from performing concurrently. In this presentation we'll discuss the true meaning of concurrency, explore the inner-workings of the GIL, and gain a deeper understanding of how the GIL effects concurrent programs. Along the way we'll write a bunch of concurrent Ruby code, run it on multiple interpreters, and compare the results.

4.
According to the Internet
• Ruby has a Global Interpreter Lock (GIL), aka Global
Virtual Machine Lock (GVL)
• The GIL is soulless, heartless, and pure evil
• The GIL hates you and wants you to be miserable
• The GIL eats babies for breakfast, kittens for desert,
and puppies for a midnight snack
• The GIL is the sole cause of climate change
• If there was no GIL there would be no war

9.
More Rob Pike
• Concurrency is about dealing with lots of things at
once.
• Parallelism is about doing lots of things at once.
Rob Pike
"Concurrency is not Parallelism"
https://talks.golang.org/2012/waza.slide#8

10.
Concurrency vs. Parallelism
• Parallelism requires two processor cores
– No matter the language/runtime
– A processor core can only execute one instruction at a
time
• Concurrency can happen when there is only one
core
– Concurrency is about design
– Improved performance is a side effect

14.
The “L” in GIL means “lock”
• A “lock” in computer science is a synchronization
mechanism which ensures that only one thread can
access a protected resource at any given time
• A thread needing to access a protected resource
must request the lock
– If the lock is available it is acquired
– If not, the thread blocks and waits for the lock to become
available

15.
What is a thread?
• A thread of execution is the smallest sequence of
programmed instructions that can be managed
independently by a scheduler – Wikipedia
• Most modern operating systems use threads for
enabling concurrent tasks within individual
programs
• The number of threads running at any given time,
across all programs, vastly exceeds the number of
processor cores on the syste

16.
What is a thread?
• Many programming languages (Ruby, Java) map
language constructs directly to operating system
threads
• Some programming languages (Erlang, Go) place an
abstraction over native threads and provide their
own scheduler
• Regardless of the language, you still have threads
within the operating system

17.
Multithreading in the OS
• The operating system must manage threads of
execution across all running programs
– Remember, each core can only run one thread
• When the operating system pauses the execution of
one thread to resume execution of another it’s
called a “context switch”
• No programming language can preempt an
operating system context switch
– Even a single-thread program
– At best, we can give it suggestions and hints

18.
Getting back to the GIL
• Every programming language/runtime must have
internal logic to manage itself across operating
system context switches and across its own
concurrency constructs
• Some languages run one thread per processor and
handle context switching internally
• Other languages let the operating system manage
all concurrency and context switching

19.
Ruby uses the GIL to protect its internal
state across OS context switches

20.
How the GIL works (simplified)
• Thread A begins some work
– Ruby locks the GIL to protect its internal state
• A context switch occurs and Thread B runs
– Thread B attempts to acquire the GIL, but fails
– Thread B signals the OS that it’s done for now
• Eventually Thread A is resumed by the OS
– When done, Thread A releases the GIL
• On the next context switch Thread B can acquire the
GIL

21.
Implications of the GIL
• Only one “unit” of Ruby code can execute at any
given time
– Although there may be multiple threads and multiple
processors, executing code will regularly be blocked by
the GIL
• When given multiple cores Ruby is unable to
experience true parallelism
• The Ruby runtime guarantees that it will always be
in a consistent internal state
– But it makes no guarantees about your code

22.
The obligatory word definition
guar·an·tee
/ˌɡerənˈtē/
noun
1. a formal promise or assurance (typically in writing) that certain
conditions will be fulfilled, especially that a product will be repaired or
replaced if not of a specified quality and durability.
verb
1. provide a formal assurance or promise, especially that certain
conditions shall be fulfilled relating to a product, service, or
transaction.
Google

23.
Share and share alike
• Ruby is a “shared memory” language
• All variables are references
– The variable itself is simply a memory address
– The data is stored at the references memory location
• Two variables may reference the same memory
address
• Two threads may share data by simultaneously
accessing the same memory location

25.
Correct vs. safe
• In a fully parallel, shared memory system it is
possible for two or more threads to simultaneously
access the same memory
• In a concurrent, shared memory system it is
possible for a context switch to occur while one
thread is in the process of performing complex
memory altering operations
• The ordering of these operations is important

26.
Ruby is selfish
• Ruby is an interpreted language
– Ruby is compiled to bytecode within the interpreter
– Ruby is free to optimize and reorder your code
• Every Ruby operation is implemented in C
• The Ruby runtime is just another program; it is under
the control of the compiler and the operating system
– The C compiler is free to optimize and reorder instructions
during compilation
– An operating system context switch can occur at any point in
the running C code
• The GIL protects Ruby, not your code

27.
Ruby is thread safe, your code isn’t
• Every individual read and write to memory is
guaranteed to be thread-safe in Ruby
– The GIL prevents interleaved access to memory used by
the runtime
– The GIL prevents interleaved access to individual
variables
– Ruby itself will never become corrupt
• Ruby makes no guarantees about your code

28.
Memory model
• “In computing, a memory model describes the
interactions of threads through memory and their
shared use of the data.” Wikipedia
• Defines visibility, volatility, atomicity, and
synchronization barriers
• Java’s current memory model was adopted in 2004
as part of Java 5
• The C and C++ memory models were adopted in
2011 with C11 and C++11

33.
I/O, I/O, it’s off to work I go
• Modern computers support both blocking and
asynchronous (non-blocking) I/O
– Blocking: the process must wait for I/O to complete
before it continues
– Asynchronous: request an I/O operation from the OS then
do something else while I/O is in progress
• I/O in Ruby programs is blocking
• I/O within Ruby is asynchronous

34.
All Ruby I/O calls unlock the GIL,
as do backtick and `system` calls

35.
When Ruby thread is waiting on I/O it
does not block other threads

36.
You can’t spell GIL without I/O
• The GIL exists to maintain the internal consistency
of the Ruby runtime
• I/O operations are slow, which is why asynchronous
I/O was invented
• While I/O is in progress the Ruby thread is blocked
so it cannot change the internal state
• So Ruby allows other threads to do useful work

38.
You may be concurrent if…
• Does your program do these things?
– Read/write from files (such as logs)
– Interact with databases
– Listen for inbound network requests (say, HTTP)
– Connect to external HTTP APIs
– Send email
• If so, then your program may benefit from
concurrency

39.
Lack of knowledge
• Most Ruby programmers never write concurrent
code
• Often concurrency is managed by the frameworks
we use (Rails)
• Many of the domains requiring highly concurrent
code also need high performance so they are
written in other languages
• So learning about concurrency simply isn’t
necessary for many in the Ruby community

40.
Concurrency in Ruby isn’t perfect
• Ruby is good at concurrent I/O; not so much for
processor intensive operations
• The GIL prevents full parallelism
– The operating system will still multiplex across multiple
Ruby threads
– But many context switches will result in a no-op because
the GIL is locked
• Some programs will gain no performance benefit
from concurrency

43.
Summary
• Concurrency is not parallelism
• The GIL protects Ruby’s internal state when the
operating system context switches
– The GIL does not provide thread safety guarantees to
user code
– But it imposes an implicit memory model
• The GIL prevents true parallelism in Ruby
• But Ruby is pretty good at multiplexing threads
performing blocking I/O