Threads is not executing in parallel python with ThreadPoolExecutor
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
Python has been a popular programming language for various domains due to its simplicity and rich standard library. One of the interesting aspects of Python is its support for concurrent programming. However, many developers face confusion when they find that threads created using `ThreadPoolExecutor` do not execute in parallel, even though they expect them to do so. This article delves into why this happens and explains the nuances of Python's threading model.
Why Threads Do Not Run in Parallel
At the core of the confusion is Python's Global Interpreter Lock (GIL). The GIL is a mutex that protects access to Python objects, preventing multiple native threads from executing Python bytecodes simultaneously. This is a significant limitation when it comes to threading in Python.
What is the GIL?
- Purpose: The GIL ensures that only one thread executes Python bytecode at a time. This simplifies memory management and integrates with Python's C libraries.
- Impact: It means that even if you have a multicore processor, Python threads will not make full use of multiple cores. Instead, they execute in an interleaved manner.
Demonstration With `ThreadPoolExecutor`
Let's consider a simple example using `ThreadPoolExecutor`.
- Here, `ThreadPoolExecutor` is initialized with `max_workers=2`, meaning at most two threads can run concurrently.
- Despite having four tasks, only two can start at once due to the limit set by `max_workers`.
- Threads are launched and pick tasks, but due to the GIL, they do not proceed in a true parallel manner if they involve Python bytecode.
- I/O-bound operations: When a thread is waiting for I/O operations (e.g., network, file I/O), another thread can take over the execution, thus benefiting from concurrency.
- Native extensions: If the code involves C extensions that release the GIL, such sections can run in parallel.
- Here, `requests.get()` waits for network responses, which allows other threads to utilize CPU time, benefiting from concurrency.
Related reading
- Threads vs. Async
- Threads vs Asynchronous Networking Twisted Python
- Threads vs Processes in Linux
- Thread.sleep VS Executor.scheduleWithFixedDelay
- thresholds in roc_curve in scikit learn
- Tie breaking in a priority queue using python
- Thread.Start versus ThreadPool.QueueUserWorkItem
- ThreadStart with parameters
.png&w=3840&q=75)
Tackling System Design Interview Problems
A short course that equips you with the skills to approach system design interviews methodically.
Start the free courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.