We’ll be covering the following topics in this tutorial:
What is Multitasking in Python?
In general, Multitasking can be defined as “performing multiple tasks of one process at one time.“. In technical terms, Multitasking refers to an operating system’s ability to perform several different tasks simultaneously. For example, you’re installing something on your PC, such as game, and you’re concurrently playing a music. The same OS does both these tasks, and activities are executed in sync. It is nothing but Multitasking and aims to save time in addition to increasing productivity.
Types of Multitasking are:
When several tasks are executed simultaneously, each task has a separate independent process known as process-based multitasking. E.g., While we do coding in Python in the editor, we can listen to songs at the same time from the same system in the background. Process-based multitasking is the best option for operating system level.
What is a Process?
A process is our running program. For example, if you run a browser, it’s a process. If you run a video game, it’s a process now inside this process, multiple threads can work together to accomplish a common goal, and threads allows the program to run in parallel. That is the single most important benefit of using threads so let me give you an example. When you play a video game, it has to handle a few tasks. For example, it has to handle the graphics and the user interface. If you are playing the multiplayer game, it has to handle the networking and all those things it has to handle in parallel because it has to remain responsive at all times.
How does this video game handle those parallel tasks?
A simple answer is threaded. It can assign one thread for graphics, one thread for the user interface, and another thread for networking, so by using threads, the beauty game can always remain responsive, and it can run the task in a parallel way now, let me explain threads using this diagram.
In the process, you can see three threads. Inside those threads, you can see a code and a local variable, so a thread is a light-weight process that exists inside the process. Also, a thread is a sequence of control flow. The thread and process difference is that the thread exists entirely inside the process and shares its resources.
Let’s say inside the box. We have the global variables that each thread will share global variables. Each thread can also have its local variables and its control flow to work with those local and global variables. A single process may have multiple threads of execution, and as I already said, threads are useful when an application wants to perform many concurrent tasks on shared data. Now, let me give you one more example.
Think about a browser. It has to handle the landing pages or the animations or if you want to open multiple websites on different tabs. You want to run a video in one tab, and if you’re going to do another task in another tab, most of the time, the browser always remains responsive. The browser can handle multiple tasks simultaneously. It uses threads still to stay responsive.
What is a thread?
A thread is a sequential independent flow of execution. Threads allow a program to split itself into two or more tasks to run at the same time. A single process can consist of multiple threads. Each thread in a program performs a particular task. For Example, when you are playing a game, say GTA, on your PC, the game will consider as a single process. Still, it consists of several threads responsible for playing the music, taking input from the user, running the opponent synchronously, etc. All these are separate threads responsible for carrying out these different tasks in the same program.
A single process always has one thread. All kinds of operating systems have different types of threads and processes. However, threads within the same process share the same resources, while different processes in the same multitasking operating system do not share the same resources. Threads are lighter than processes they use low resources compared to processes.
There are two different kinds of threads:
A kernel thread and the other is a user-space thread or a user thread. Kernel threads are part of the operating system. While user-space threads are not implemented in the kernel, the user-space threads can be seen as an extension of function concepts in programming languages. Now each process has at least one, and that is the main thread. If you don’t even create a thread inside a process, it has at least one thread, which is the process itself.
What is Multiprocessing?
You can run multiple unrelated processes simultaneously through multiprocessing. These processes do not share their resources and communicate via IPC.
When to use Multithreading in Python?
Multithreading in Python is very useful if the multiple threads perform mutually independent tasks not to affect other threads. Multithreading is very useful in speeding up computations, but it can not be applied everywhere.
In the previous example, the music thread is independent of the input thread running the opponent, but the input thread is still independent. These threads run individually because they do not depend on each other.
Multithreading will only be used if each thread is independent.
How to achieve Multithreading in Python?
To achieve multi-threading in Python, two modules support Multithreading, and these two modules are the thread module and the threading module. There is one thing to note here that the thread module has been considered as deprecated for quite a long time, so users are often encouraged to use that threading module instead of the thread module to see in
Python 3. thread module is directly not available. Still, indirectly you can use underscore thread to use the thread module, and this is to remain backward with the previous versions of Python. The thread module and the threading module’s difference is that the thread module treats the thread as the function. In contrast, module threading is implemented in an object-oriented way.
How to use the threading module to create threads in Python?
Threads in Python can be created in three ways:
Multithreading in Python without making a class
You can make multithreading in Python without making a class. Here is an example:
import time from threading import * print(current_thread().getName()) def first_Thread(): print ("First Child Thread Running") time.sleep(1) print ("First Child Thread Done") def Second_Thread(): print ("Second Child Thread Running") time.sleep(1) print ("Second Child Thread Done") Thread(target=first_Thread).start() Thread(target=Second_Thread).start()
The first thread is the main thread. This main thread then produces a child thread, which subsequently executes the same code section, which is executed once again by the main thread.
First, let us look at how we can use multi-threading with the Thread class.
Create Thread by extending Thread Class:
The Thread class should be extended by adding a child class. When adding a new class, Thread’s child can only override two methods: the
__init__() method and the
It is an example of extending the Thread class to create a thread.
from threading import * class Mythread(Thread): def run(self): for i in range(2): print('Hi Child Thread') t = Mythread() t.start() for i in range(1): print('Main Thread')
The above example shows that class Mythread is inheriting the Thread class and the child class i.e Mythread is overriding the run method. By default, the first parameter of any class function needs to be self which is the pointer to the current object. The output shows that the child thread executes the run() method and the main thread waits for the childs execution to complete. This is because of the join() function, which makes the main thread wait for the child to finish.
This example illustrates that child class Mythread inherits the Thread class and overrides its run method. Whenever possible, any class function must start with self. The child thread executes the run() method, and the main thread waits for the execution to be complete. For this reason, child threads can be derived from the main thread.
Thread creation is the method that is the most common to use. However, if you want to create threads without inheriting or extending the Thread class, the process is as follows.
Create Thread without extending Thread Class :
To create a thread without extending the Thread class, you can do as follows:
from threading import * class Mythread: def run(self): for i in range(2): print('Child Thread') obj = Mythread() thread_obj = Thread(target=obj.run) thread_obj.start() for i in range(1): print('Main Thread')
The child thread executes Mythread after which the main thread executes the last print statement.
Advantages of Threading
Multithreading has many advantages some of which are as follows:
• A program can remain responsive to input at all times. It is true both for single and multiple CPU computer systems.
• Allows doing something else while a thread is waiting for IO tasks or any other tasks to complete, so it always remains responsive.
• Some programs are easy to express using concurrency, which leads to an elegant solution, and as a result, they are easier to maintain and debug. Some programs or some processes are inherently concurrent.
• Threads of the process can share the memory of the global variable.
As I have already shown you in the diagram previously, multiple threads can simultaneously share the global variables’ memory. If a global variable is changed in one thread, this change is valid for all the threads. A thread can have local variables also as we have seen in the diagram.
issues or challenges for threads in Python
Scheduling: To execute a threaded program, it must rapidly switch between threads. A program should be able to switch between threads gently and conveniently.
Resource Sharing: As I told you that multiple threads could share the same memory of the global variables. Since threads share this memory and other resources, it must be careful because the operation performed in one thread could cause the problem in another thread.
Synchronizing: Threads often need to coordinate their actions and as a software developer. You may have heard about the race condition of threads, which means the outcome depends on the order of thread execution and often on synchronization. We use locking primitives now that was the general description about threads.