DEV Community

Cover image for Global interpreter lock
Santanu Bhattacharya
Santanu Bhattacharya

Posted on

Global interpreter lock

What is GIL in Ruby?

GIL stands for Global Interpreter Lock. It's a mutex (mutual exclusion) used by Ruby’s interpreter — specifically MRI (Matz’s Ruby Interpreter), the default Ruby implementation — to ensure only one thread executes Ruby code at a time.

📌 Why does GIL exist?

Ruby (MRI) is written in C. The GIL is used to:

Simplify memory management in MRI’s C-based interpreter.

Avoid race conditions in the Ruby interpreter internals (especially garbage collection).

🧵 How does it affect threads?

Even if you write multi-threaded Ruby code, only one thread executes at a time (in terms of Ruby code execution). The threads take turns, not run in true parallel — this is known as cooperative concurrency.

Example:

threads = 10.times.map do
  Thread.new do
    1_000_000.times { |i| i * i }
  end
end

threads.each(&:join)
Enter fullscreen mode Exit fullscreen mode

Even though there are 10 threads, due to GIL, only one will run Ruby code at any given time (on a single core). Only one thread will execute Ruby code at a time, regardless of how many CPU cores your machine has.

🧵 But threads are still useful when...

Even though only one thread runs Ruby code at a time, I/O operations release the GIL, so:

✅ Multi-threading works well for:

  1. HTTP/network requests (e.g., Net::HTTP, open-uri)
  2. File I/O
  3. Database queries
  4. Sleeping/waiting
require 'net/http'
require 'uri'

urls = [
  'https://santattech.com',
  'https://google.com',
  'https://qi.com'
]

threads = urls.map do |url|
  Thread.new do
    response = Net::HTTP.get(URI(url))
    puts "#{url} - #{response.bytesize} bytes"
  end
end

threads.each(&:join)
Enter fullscreen mode Exit fullscreen mode

Here, each thread will process an I/O HTTP request. So, GIL will be released.

⚙️ What is parallel then?

Ruby threads can still benefit from parallelism when:

They are waiting on I/O (e.g., file reads, network).

They are running native extensions or C code that release the GIL (e.g., some database drivers, image processing libraries).

So, GIL doesn't block concurrency, but it limits parallelism in CPU-bound Ruby code.

🚀 Alternatives to bypass GIL:

Use processes instead of threads
Use Process.fork or tools like:

  1. parallel gem
  2. sidekiq (for background jobs)

Parallel gem internally uses Process.fork

require 'parallel'

results = Parallel.map([1, 2, 3, 4, 5], in_processes: 3) do |i|
  puts "PID #{Process.pid} is processing #{i}"
  sleep 1
  i * i
end

puts "Results: #{results.inspect}"

Enter fullscreen mode Exit fullscreen mode

NB: I think parallel gem is available inside Rails by default from Rails 7.

Use JRuby

These alternative Ruby implementations don’t have GIL, so they support true parallel threading on multicore CPUs. It uses the JVM (Java Virtual Machine), allowing true multi-threading.

RUBY

JRUBY

Conclusion

GIL is not a problem when the application is doing HTTP requests, I/O operations or the file operations. Also, GIL makes the Ruby code execution simpler & safer, though multi-threading is not allowed. If you need multi-threading can opt for JRuby.

Top comments (0)