GIL and why your multithreaded Python code is probably single-threaded
The Python Global Interpreter Lock or GIL, in simple words, is a mutex (or a lock) that allows only one thread to hold the control of the Python interpreter in CPython.
This means that only one thread can be in a state of execution at any point in time. The impact of the GIL isn’t visible to developers who execute single-threaded programs, but it can be a performance bottleneck in CPU-bound and multi-threaded code.
It's also worth noting that CPython is not the only implementation of Python, other implementations such as Jython, IronPython and PyPy have different approaches to handle threading and don't have the GIL.
What Problem Did the GIL Solve for Python?
Python uses reference counting for memory management. It means that objects created in Python have a reference count variable that keeps track of the number of references that point to the object. When this count reaches zero, the memory occupied by the object is released.
Let’s take a look at a brief code example to demonstrate how reference counting works:
>>> import sy
>>> a = []
>>> b = a
>>> sys.getrefcount(a)
3s
In the above example, the reference count for the empty list object [] was 3. The list object was referenced by a, b and the argument passed to sys.getrefcount().
Back to the GIL:
The problem was that this reference count variable needed protection from race conditions where two threads increase or decrease its value simultaneously. If this happens, it can cause either leaked memory that is never released or, even worse, incorrectly release the memory while a reference to that object still exists. This can cause crashes or other “weird” bugs in your Python programs.
This reference count variable can be kept safe by adding locks to all data structures that are shared across threads so that they are not modified inconsistently.
But adding a lock to each object or groups of objects means multiple locks will exist which can cause another problem—Deadlocks (deadlocks can only happen if there is more than one lock). Another side effect would be decreased performance caused by the repeated acquisition and release of locks.
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.
The GIL, although used by interpreters for other languages like Ruby, is not the only solution to this problem. Some languages avoid the requirement of a GIL for thread-safe memory management by using approaches other than reference counting, such as garbage collection.
On the other hand, this means that those languages often have to compensate for the loss of single threaded performance benefits of a GIL by adding other performance boosting features like JIT compilers.
Is writing a multithreaded program pointless?
Like most things in software engineering it depends.
First the limitation is only for Cpython if you are using any other implementation of python like Jython you can utilize the benefits of multithreading.
领英推荐
Second threading was introduced to improve the performance of applications by allowing multiple tasks to be executed simultaneously, reducing thread blocking. Nowadays, thread blocking can occur due to either CPU-intensive tasks or I/O-bound tasks. I/O-bound tasks are those that spend a significant amount of time waiting for input or output from sources such as users, files, databases, or networks. These tasks may have to wait for a significant amount of time as the source may be busy with its own processing. However, the Global Interpreter Lock (GIL) does not have a significant impact on the performance of I/O-bound multi-threaded programs as the lock is shared between threads while they are waiting for I/O.?
Therefore, utilizing multiple threads for I/O-bound tasks can still provide significant performance benefits.
?
How to Deal With Python’s GIL
If the GIL is causing you problems, here a few approaches you can try:
It is important to note that the solution to use depends on the specific use case, and the trade-offs between performance and ease of use should be considered before making a decision.
Future of GIL
Recently a new proposal was proposed to remove GIL by? adding a build configuration (--without-gil) to CPython to let it run Python code without the global interpreter lock and with the necessary changes needed to make the interpreter thread-safe.
You can read more about it here?
References?
Software Engineer 2 | Backend Engineer at Microsoft
9 个月Pranav Pandey one fundamental question. Does this means using condition variables in python could lead to deadlocks in CPython implementation? Condition variables can put the current thread into waiting state unless some another thread wakes it up. Or is it that when a thread goes into wait state, the GIL on the interpreter is released, and it allows other threads to execute.
Site Reliability Engineering Manager at LinkedIn | Ex-Ola
1 年Nice writeup !!
Senior Software Engineer @Headout | Building @bhagavadgita.tech | Ex- SDE @Localeai @Lyearn @Atlan @Appbase @fossasia | GSoC '18 | DA-IICT
1 年Great article Pranav Pandey ??, loved it ??!
Software Engineer III @ Google | ACM-ICPC Regionals 2019
1 年Interesting!!
Hemvati Nandan Bahuguna Garhwal University ( A Central University )
1 年Helpful!