Suppose you are familiar with coding in the Python programming language. In that case, there must have been many instances where you just wanted to speed up the entire process by executing multiple tasks at once or by interleaving numerous tasks. Both approaches are possible in Python and are known as Concurrency and Parallelism.
There are two extents to which you can speed up your processes – I/O and CPU Consumption. If your code involves a lot of files accessing and similar repetitive tasks, it is I/O bound. On the other hand, if your code includes a lot of heavy computations, it is indeed CPU bound. Both types of tasks differ in terms of the resources they require. When an I/O bound code is running, it is not using the CPU’s core that much because it is sitting idle waiting for the responses to be received. We cannot improve this process by adding more computational power. The reverse is the same for CPU-bound code.
To remove either of the bottlenecks, we use the two mechanisms, i.e., Concurrency & Parallelism.
Concurrency v/s Parallelism
Concurrency means doing multiple things at once. However, Concurrency takes up a slightly different approach in python programming. Concurrency in Python is managing alternate jobs at the same time. It means that the python runtime executes not all jobs or tasks at once; instead, they alternate to achieve optimum efficiency. Concurrency involves multiple tasks taking turns accessing the shared resources.
While, on the other hand, Parallelism does mean that multiple jobs or tasks are executed simultaneously by the python runtime. In Parallelism execution, several tasks are allowed to run side-by-side on independently partitioned resources.
Concurrency and Parallelism both have different aims and solutions that they bring to the table. Concurrency’s goal is to prevent various tasks from blocking by switching among them while waiting on an external resource. To achieve Concurrency, the Python runtime completes multiple network requests.
Usually, when the user launches one request, it takes time to finish, which is the waiting period, and then the next one is launched. A concurrent way of doing this is to launch all requests simultaneously and switch among them as we get the responses.
Contrastingly, Parallelism maximizes the hardware used. For example, if you have eight cores in your CPU, you do not want to maximize on one while the other seven cores sit idle; you would like to launch processes that utilize all eight cores at once.
Implementing Concurrency & Parallelism in Python
Python permits the usage of both Concurrency and Parallelism with its syntaxes and uses cases. In Python, Concurrency is implemented by threading and coroutines, or async. And Parallelism by Multiprocessing.
Let’s have a look at the advantages and disadvantages of all three methods:
Threading helps you create multiple threads across which you can distribute I/O bound workload. One noteworthy thing about threading is that it does not work the same way it works in other programming languages like Java. For example, Java’s Global Interpreter Lock (GIL) ensures that only one thread is in processing at a time and memory usage is thread-safe.
Advantages of Python Threads
Threads in Python are a convenient and well-understood way of running tasks that waits on other resources. Apart from this, Python’s standard libraries have high-level conveniences for running operations in threads.
Disadvantages of Python Threads
Python threads are cooperative, which means that the Python runtime divides its attention between them. As a result, Threads are not suitable for a task that is CPU intensive because if we run a CPU intensive task in threads, the runtime will pause it while switching to a different thread so, there is no performance benefit overrunning that task outside of the thread.
Another disadvantage of using threads in Python is that the developer needs to manage the state between them. We must manually synchronize different threads to expect the desired results, an overly complex task.
- Python coroutines, or async
Coroutines or async is an alternate method of running tasks simultaneously in Python. Instead of using multiple threads, coroutines use special programming constructs and all the tasks run on a single thread.
Advantages of Python coroutines
With Coroutines, you can quickly tell which programs are running side by side by looking at the syntax. With threads, this is not possible; any function might be running in a thread.
Another advantage of Coroutines is that they are free from architectural limitations faced by threads. Switching between many coroutines in a program is easy and requires less memory than threads.
Disadvantages of Python coroutines
Writing code for Python coroutines is a little complex as it requires the programmer to write it in its distinct syntax, making its mingling impossible with synchronous code design-wise. Using coroutines can be a little tricky for programmers who are not used to writing their code asynchronously. Also, you cannot run CPU-intensive tasks side by side efficiently.
Multiprocessing in Python allows us to run numerous CPU-intensive tasks simultaneously by launching multiple, independent copies of Python runtime. Multiprocessing leverages each core in your CPU by creating a python interpreter for each process.
Advantages of Python Multiprocessing
Multiprocessing is better than async or threading because it sidelines their limitation of the python runtime forcing all the operations to run serially by giving each process a separate python runtime and an entire CPU core.
Disadvantages of Python Multiprocessing
The first downside of Python Multiprocessing is the additional overhead associated with creating the processes. Another downside is that each subprocess requires a copy of data sent from the primary process.
Best Method to use
If you are dealing with long-running, CPU-intensive operations, use multiprocessing. If you are dealing with long-running, CPU-intensive operations, use multiprocessing.
On the other hand, if you perform functions that do not involve CPU but wait on external resources, use threading or async. Async is favorable to threads for long-running IO operations. And, if your IO-bound operations are fast, go with multi-threading.
As of today, Python programming language is the most preferred language for Artificial Intelligence, Robotics, Web Development, and DevOps.
Hope you found this blog useful. Cheers and good luck with your future.
Want to kickstart your career as Python Developer? We at Consultadd are investors in people and have got you covered!
Connect with our team now and start your career as a Python Developer.