What is Global Interpreter Lock in Relation to Ruby?

A few days ago, I came across something about Global Interpreter Lock (GIL) limitations in Ruby and I had no idea what it was. So naturally, I decided to research it. Similar to my last blog post, it’s important to know what goes on in the background when we execute code. Please note that GIL is not exclusive to the Ruby engine but simply something that Ruby MRI (Matz’ Ruby Interpreter) implements. For example, CPython uses GIL as well.

Before we cover what GIL is, let’s address some concepts first. Please keep in mind, when I discuss these concepts, I will be talking in the context of Ruby MRI.

Concepts

1) Thread(s)

2) Race condition

Thread(s)

Think of threads as an execution path of statements as per your code.

Image from Wikipedia

You probably also heard of the term single threaded or multi-threaded before. Single threaded means one thing can run at a time while multi-threaded means you can run multiple things at a time. The picture above shows us how threads in Ruby MRI run concurrently but not parallel. To provide an example, think about this. You just executed your code and you have two threads. Those two threads are “fighting” with each other to finish executing themselves. Each one would execute for a certain amount of time and it would go back and forth between each other.

Race Condition

Race condition refers to when the result of a thread or threads is dependent on the sequence of events. This can be quite problematic and can cause bugs. I provided an example down below.

@counter = 0100.times.map do
Thread.new do
10000.times do
value = @counter
value = value + 1
@counter = value
end
end
end.each(&.join)
puts @counter

Picture A

If you were to run the code above in Picture A several times, you’d get the same result every time which is 1,000,000. (Keep in mind, I’m running this on Ruby 2.5.5.)

@counter = 0def read_counter
@counter
end
def add_value(value)
@counter = value
end
100.times.map do
Thread.new do
10000 times do
value = read_counter
value = value + 1
add_value(value)
end
end
end.each(&:join)
puts @counter

Picture B

Although I rearranged the code in Picture B, it’s essentially the same. Try running the code I have in Picture B several times. You’d get several different outputs. This is an example of race condition. Because of this, this makes the code unreliable.

Global Interpreter Lock (GIL)

GIL or global interpreter lock makes it so only one thread runs at a time, preventing threads from running concurrently. Hence, the “lock” portion of the name. This can prevent race conditions from occurring, making it harder for data to become corrupt. Keep in mind that GIL is not perfect and can work depending on how your code is written and the version of Ruby you’re using. GIL has limitations. GIL was not created for us, but for developers.

--

--

--

Flatiron School Alumni & Software Engineer https://jonathanwong110.github.io/JonathanWongPortfolio/

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Compact on Close Danger

Anatomy of Kubeflow Pipeline

15 Must-Have Visual Studio Extensions for Developers

Your Tech Curator. (I collect latest tech news just for you)

Deploying Prometheus and Grafana with Helm

The Escape Button Is A Feature!

Full Automation and Integration of Git, Jenkins, Docker and Kubernetes

Scrape Monster.fi and… (Part 1)

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Jonathan Wong

Jonathan Wong

Flatiron School Alumni & Software Engineer https://jonathanwong110.github.io/JonathanWongPortfolio/

More from Medium

The Imposter Syndrome in Software Development

Most important Software Design Patterns

My Journey into Software Development (Intro)

Software engineering principles, Best practices and Introduction to JavaScript