multithreading
multithreading
1-Python Multithreading:
A thread is the smallest unit of a program or process executed independently or scheduled by the
Operating System. In the computer system, an Operating System achieves multitasking by dividing the
process into threads. A thread is a lightweight process that ensures the execution of the process
separately on the system. In Python 3, when multiple processors are running on a program, each
processor runs simultaneously to execute its tasks separately.
3. It shares resources and its state with sub-threads (child) which makes it more economical.
6. The system does not require too much memory to store multiple threads.
It is a very useful technique for time-saving and improving the performance of an application.
Multithreading allows the programmer to divide application tasks into sub-tasks and simultaneously
run them in a program. It allows threads to communicate and share resources such as files, data, and
memory to the same processor. Furthermore, it increases the user's responsiveness to continue
running a program even if a part of the application is the length or blocked.
In Python, threads and processes are two different approaches for achieving parallelism, and they are
used based on different requirements. Let's break them down:
1. Threads:
Definition: A thread is a smaller unit of a process that can run concurrently. Multiple threads can exist
within the same process and share the same memory space.
Module: The threading module in Python provides support for working with threads.
Use Case: Threads are suitable when you need to perform I/O-bound tasks, like reading/writing files or
network operations, as Python's Global Interpreter Lock (GIL) restricts CPU-bound tasks from truly
running in parallel in the same process.
Key Features:
Shared memory space: Threads can communicate and share data easily.
Python threads are limited by the GIL, so only one thread executes Python bytecode at a time (in Python),
even on multi-core systems.
2. Processes:
Definition: A process is an independent entity that has its own memory space. Unlike threads,
processes do not share the same memory space.
Module: The multiprocessing module in Python provides support for spawning processes.
Use Case: Processes are used when you want to achieve true parallelism for CPU-bound tasks (like
heavy computations), because each process gets its own Python interpreter and memory space, and
is not affected by the GIL.
Key Features:
Separate memory space: Processes do not share memory by default (inter-process communication
can be achieved with pipes, queues, etc.).
True parallelism since processes are independent and not restricted by the GIL.
Memory: Threads share the same memory, whereas processes have separate memory.
GIL: Python's GIL affects threads, limiting their ability to execute concurrently for CPU-bound tasks.
Processes are not affected by the GIL.
Overhead: Threads are lightweight and faster to create, but processes are heavier due to the need for
separate memory space.
Communication: Threads can communicate directly through shared variables, but processes need
explicit mechanisms (like queues, pipes) for communication.
In summary:
Use threads when your task is I/O-bound (e.g., reading files or making network requests).
Use processes for CPU-bound tasks to bypass the GIL and achieve true parallelism.
3-How to achieve multithreading in Python?
There are two main modules of multithreading used to handle threads in Python.
3.1-Thread modules - A thread is an entity within a process that can be scheduled for execution. Also,
it is the smallest unit of processing that can be performed in an OS (Operating System). In simple words,
a thread is a sequence of such instructions within a program that can be executed independently of
other codes.
It is started with Python 3, designated as obsolete, and can only be accessed with _thread that supports
backward compatibility.
Syntax:
example:
def country(m):
time.sleep(0.5)
_thread.start_new_thread(name,("sai",))
_thread.start_new_thread(country,("india",))
output:
Types of Threads
As the name suggests, the user-level threads are only managed by users, and the kernel does not have
its information.
2. Kernel-Level Thread
The kernel-level threads are handled by the Operating system and managed by its kernel. These threads
are slower than user-level threads because context information is managed by the kernel. To create and
implement a kernel-level thread, we need to make a system call.
Features of Thread
• Threads share data, memory, resources, files, etc., with their peer threads within a process.
• Threads can directly communicate with each other as they share the same address space.
3.2-Threading Modules
The threading module included with Python 3.4 provides much more powerful, high-level support for
threads than the thread module .To use multithreading, we need to import the threading module in
Python Program.
The threading module exposes all the methods of the thread module and provides some additional
methods −
• threading.currentThread() − Returns the number of thread objects in the caller's thread control.
• threading.enumerate() − Returns a list of all thread objects that are currently active.
In addition to the methods, the threading module has the Thread class that implements threading. The
methods provided by the Thread class are as follows −
• start() − The start() method starts a thread by calling the run method.
Apart from the functions specified above, the threading module also provides many classes whose
objects are very useful in creating and managing threads.
Object Description
Bounded Semaphore Similar to a Semaphore but ensures that it never exceeds its
initial value.
Timer Similar to Thread, except that it waits for a specified period
of time before running.
Barrier Creates a "barrier" at which a specified number of threads
must all arrive before they're all allowed to continue.
A global interpreter lock (GIL) is a mechanism to apply a global lock on an interpreter. It is used in
computer-language interpreters to synchronize and manage the execution of threads so that only one
native thread (scheduled by the operating system) can execute at a time.
In a scenario where you have multiple threads, what can happen is that both the thread might try to
acquire the memory at the same time, and as a result of which they would overwrite the data in the
memory. Hence, arises a need to have a mechanism that could help prevent this phenomenon.
Some popular interpreters that have GIL are CPython and Ruby MRI. As most of you would know that
Python is an interpreted language, it has various distributions like CPython, Jython, IronPython. Out of
these, GIL is supported only in CPython, and it is also the most widely used implementation of Python.
CPython has been developed in both C and Python language primarily to support and work with
applications that have a lot of C language underneath the hood.
Hence, GIL (Source: Understanding the Python GIL):
• The GIL ensures that only one thread runs in the interpreter at once.
The impact of the GIL isn’t visible to developers who execute single-threaded programs. Since the GIL
allows only one thread to execute at a time even in a multi- threaded architecture with more than one
CPU core, the GIL has gained a reputation as an “infamous” feature of Python.
Python Global Interpreter Lock (GIL) is a type of process lock which is used by python whenever it deals
with processes. Generally, Python only uses only one thread to execute the set of written statements.
This means that in python only one thread will be executed at a time. The performance of the single-
threaded process and the multi-threaded process will be the same in python and this is because of GIL
in python. We cannot achieve multithreading in python because we have global interpreter lock which
restricts the threads and works as a single thread.