Global Interpreter Lock in Python
Global Interpreter Lock (GIL) is a feature of a Python language and something one must be aware about when trying to use more than one processor of a computer. GIL in a nutshell is a lock that lets only one thread to access Python interpreter at a time.
In this article, we are going to know about what GIL is, how it is different from other programming languages and how it is overcome.
The time I came across this GIL, and not fish’s gill, was during an interview. Being a generalist and still not dived deeply into the language, it piqued my curiosity and learned more about it after the interview. It gave me a gist of how single-threaded and muti-threaded and computation heavy code is executed differently in Python due to this GIL.
Let see an example:
If there are four processors in a computer, a computer should use all the four processors to make use of the resources else why are they there? Hence, tasks to be performed are in a ready queue ordered by Operating System’s scheduler ready to perform a task in an available processor. Diagrammatically, this is what it would look like.
This is what happens in most programming languages like Java, C++.
Thread execution in Python is quite different. Again, let’s say we have four processor in a computer, and four threads in a ready queue. The Operating System would choose the first thread from the ready queue to execute in one of the four available processors. The rest three would be in a waiting queue. These three threads would be woken up after there is an interruption after a specific time period or executing threading is waiting for I/O.
The executed thread will go back to the ready queue and the three threads in a waiting queue would be moved back to the ready queue. The Operating System orders one of the three threads from the waiting queue to be executed by a processor. The remaining three would go back to the waiting queue. This process continues until all the threads are done performing their task.
Diagrammatically, this is what it would look like:
That’s it. GIL allows only one thread to have an access to the Python interpreter. One of the reason for the design was to be compatible with C modules used in Python.
Let’s see an example with code that shows behavior of a single thread and multiple threads.
On running the code, the output is:
start...
end...
sum from 1..10000 is 49995000.
Took 0.000663 seconds.
It took 0.0006
seconds to compute sum from 1 to 10K.
Now let’s divide the task in two threads.
The output is:
start...
start...
end...
end...
sum from 1..5000 is 12497500.
sum from 5001..10000 is 37492500.
Took 0.001007 seconds.
It took 0.001
seconds. hmm.. higher than single threaded code which took 0.0006
seconds. You may be able to answer. Yes, Python allows only one thread to execute at a time due to GIL and by having another thread, we are basically adding overhead of context switching (ready and waiting queue) between two threads hence increasing the time.
Side note: If you are bit startled by the serial start..
and print...
statements in the output it is because once there is a computation (addition) happening, so waiting for output, it be will be put back to a ready queue and another thread from (waiting then ready queue) ready queue will be selected to be executed in a processor. This is a concurrency.
Is there a way we can make use of all the processors in a computer in Python? Yes. We have multiprocessing
module that circumvents this GIL by allowing each processor to have its own copy of GIL. With this comes overhead of more memory need and initial setup increase time as there is copy of original setup.
Well known pattern is if a program is I/O heavy single-threaded program is good else if a program is CPU heavy then multi-process program is good.
In conclusion, GIL is feature of Python language and it allows only one thread to access Python interpreter. It was done for simpler implementation of modules. We have multiprocessing
module to take care of needs where a task is computation heavy.
That’s all for this post. Thank you for reading! See you in my next post.