Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why the Global Interpreter Lock?

What is exactly the function of Python's Global Interpreter Lock? Do other languages that are compiled to bytecode employ a similar mechanism?

like image 638
Federico A. Ramponi Avatar asked Nov 05 '08 16:11

Federico A. Ramponi


People also ask

Why is global interpreter lock used?

In CPython, the global interpreter lock, or GIL, is a mutex that protects access to Python objects, preventing multiple threads from executing Python bytecodes at once. The GIL prevents race conditions and ensures thread safety. A nice explanation of how the Python GIL helps in these areas can be found here.

Why is Python global interpreter locked?

The GIL is a single lock on the interpreter itself which adds a rule that execution of any Python bytecode requires acquiring the interpreter lock. This prevents deadlocks (as there is only one lock) and doesn't introduce much performance overhead. But it effectively makes any CPU-bound Python program single-threaded.

Will Python ever remove the GIL?

Don't expect Python 3.11 to drop the GIL just yet. Merging Sam's work back to CPython will itself be a laborious process, but is only part of what's needed: a very good backwards compatibility and migration plan for the community is needed before CPython drops the GIL. None of this is planned yet.

Does C# have GIL?

C# does not have an equivalent of GIL to Python.


2 Answers

In general, for any thread safety problem you will need to protect your internal data structures with locks. This can be done with various levels of granularity.

  • You can use fine-grained locking, where every separate structure has its own lock.

  • You can use coarse-grained locking where one lock protects everything (the GIL approach).

There are various pros and cons of each method. Fine-grained locking allows greater parallelism - two threads can execute in parallel when they don't share any resources. However there is a much larger administrative overhead. For every line of code, you may need to acquire and release several locks.

The coarse grained approach is the opposite. Two threads can't run at the same time, but an individual thread will run faster because its not doing so much bookkeeping. Ultimately it comes down to a tradeoff between single-threaded speed and parallelism.

There have been a few attempts to remove the GIL in python, but the extra overhead for single threaded machines was generally too large. Some cases can actually be slower even on multi-processor machines due to lock contention.

Do other languages that are compiled to bytecode employ a similar mechanism?

It varies, and it probably shouldn't be considered a language property so much as an implementation property. For instance, there are Python implementations such as Jython and IronPython which use the threading approach of their underlying VM, rather than a GIL approach. Additionally, the next version of Ruby looks to be moving towards introducing a GIL.

like image 106
Brian Avatar answered Oct 09 '22 08:10

Brian


The following is from the official Python/C API Reference Manual:

The Python interpreter is not fully thread safe. In order to support multi-threaded Python programs, there's a global lock that must be held by the current thread before it can safely access Python objects. Without the lock, even the simplest operations could cause problems in a multi-threaded program: for example, when two threads simultaneously increment the reference count of the same object, the reference count could end up being incremented only once instead of twice.

Therefore, the rule exists that only the thread that has acquired the global interpreter lock may operate on Python objects or call Python/C API functions. In order to support multi-threaded Python programs, the interpreter regularly releases and reacquires the lock -- by default, every 100 bytecode instructions (this can be changed with sys.setcheckinterval()). The lock is also released and reacquired around potentially blocking I/O operations like reading or writing a file, so that other threads can run while the thread that requests the I/O is waiting for the I/O operation to complete.

I think it sums up the issue pretty well.

like image 26
Eli Bendersky Avatar answered Oct 09 '22 10:10

Eli Bendersky