<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Shreshthajit das</title>
    <description>The latest articles on Forem by Shreshthajit das (@shreshthajit_das_1a7b40f5).</description>
    <link>https://forem.com/shreshthajit_das_1a7b40f5</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3577315%2F6043568b-382e-4690-87c5-aeb43804005d.jpg</url>
      <title>Forem: Shreshthajit das</title>
      <link>https://forem.com/shreshthajit_das_1a7b40f5</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/shreshthajit_das_1a7b40f5"/>
    <language>en</language>
    <item>
      <title>Database handling using Python Alembic and SQL Alchemy</title>
      <dc:creator>Shreshthajit das</dc:creator>
      <pubDate>Wed, 19 Nov 2025 19:13:09 +0000</pubDate>
      <link>https://forem.com/shreshthajit_das_1a7b40f5/database-handling-using-python-alembic-and-sql-alchemy-3a12</link>
      <guid>https://forem.com/shreshthajit_das_1a7b40f5/database-handling-using-python-alembic-and-sql-alchemy-3a12</guid>
      <description>&lt;p&gt;Suppose we are working on a Python backend application, and we often make changes that require database updates. &lt;strong&gt;Alembic&lt;/strong&gt; and &lt;strong&gt;SQLAlchemy&lt;/strong&gt; are excellent solutions for using migrations in Python. They both provide a modern approach to creating and tracking all changes to your databases. &lt;strong&gt;Alembic&lt;/strong&gt; is a database migrations tool that works together with SQLAlchemy.&lt;/p&gt;

&lt;p&gt;We can initialize Alembic in our project through this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alembic init migrations
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see a new folder called migrations under the project folder. This folder will be used by Alembic to manage the migrations, revisions, and configurations.&lt;/p&gt;

&lt;p&gt;We need to first understand the Python &lt;strong&gt;SQLAlchemy&lt;/strong&gt; and what &lt;strong&gt;Alembic&lt;/strong&gt; does. What does an alembic upgrade and downgrade do? &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SQLAlchemy&lt;/strong&gt; is like an "Object Relational Mapper." When a Python class is created and defined, SQLAlchemy takes my Python class and "maps" it to a database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alembic&lt;/strong&gt; works together with SQLAlchemy to modify our database without overwriting or deleting any data. Suppose we modified our schema and want to reflect the new changes. Now, Alembic will look at the old database, then compare it to the new one we generate, and will perform the changes on our target database table. Here's an alembic migration demo file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"""Add new column 'status' to users table

Revision ID: 123456789abc
Revises: abcdef123456
Create Date: 2025-12-02 18:00:00
"""

from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = "123456789abc"
down_revision = "abcdef123456"
branch_labels = None
depends_on = None


def upgrade() -&amp;gt; None:
    """
    Upgrade migrations: apply changes to the database schema.
    Example: Adding a new column.
    """
    op.add_column(
        "users",
        sa.Column("status", sa.String(length=20), nullable=True),
    )


def downgrade() -&amp;gt; None:
    """
    Downgrade migrations: reverse the upgrade changes.
    Example: Removing the column added in upgrade().
    """
    op.drop_column("users", "status")

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's understand the alembic &lt;strong&gt;upgrade&lt;/strong&gt; and &lt;strong&gt;downgrade&lt;/strong&gt; command:&lt;/p&gt;

&lt;p&gt;Upgrade the database forward by exactly one migration step from the current version. Suppose our migrations in version files are the following:&lt;br&gt;
&lt;strong&gt;A -&amp;gt; B -&amp;gt; C&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Our current head in versions files is C but B in the database. Then type this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alembic upgrade +1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will move us from &lt;strong&gt;B → C.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Suppose our current version is C and we want to downgrade the database back by one migration step. Then we can type the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alembic downgrade -1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;moves us from &lt;strong&gt;C → B&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's say I am working in a branch where I have made some changes, and these changes affected some tables in the database by inserting a new column. Now I want to work on another branch where this feature is not implemented. In that case, if I run the project, I will get an error from the backend since the database migration occurred when I worked on the previous feature. And if we downgrade, then it will work.&lt;/p&gt;

&lt;p&gt;Every time we make changes to the schema, Alembic will autogenerate a file with a version number that stores all the changes made to the database, as well as a downgrade command to revert changes.&lt;/p&gt;

&lt;p&gt;Sometimes, more than one alembic file is generated, which is sometimes not required at all. We can simply merge them into one. To do this, we can follow the process described below.&lt;/p&gt;

&lt;p&gt;First, we can type this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alembic history
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will see something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a1-&amp;gt;b2 -&amp;gt; c3 -&amp;gt; d4 -&amp;gt; e5 -&amp;gt; f6 -&amp;gt; g7 -&amp;gt; h8 -&amp;gt; i9 -&amp;gt; j10 (head)
a1 (base).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Suppose we want to merge &lt;strong&gt;h8,i9&lt;/strong&gt; and &lt;strong&gt;j10&lt;/strong&gt; into one migration file.&lt;/p&gt;

&lt;p&gt;We will type the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alembic downgrade g7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;g7 will be the head now.&lt;/p&gt;

&lt;p&gt;Now we will move these three files into another backup folder. And then run this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alembic revision --autogenerate -m "squashed_h8_i9_j10_migrations"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can see a new migration file generated.&lt;br&gt;
Then we will give this command to upgrade the head:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alembic upgrade head
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is another approach that we can also follow. If we open any migration file, we will see that every file has a downgrade and an upgrade function. So, we can generate a new file first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alembic revision --autogenerate -m "combined-features"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we can simply take the code of the upgrade and downgrade functions from all the files that we want to remove and update this new file with this code. Then change the downrevision of that file to the revision of the previous file, which is the HEAD, and then do the upgrade.&lt;/p&gt;

&lt;p&gt;Sometimes it fails because Alembic still references a missing revision in the database. We can force stamp with --revision that exists:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alembic stamp 26429623e713
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's discuss some issues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scenario 1:&lt;/strong&gt;&lt;br&gt;
Sometimes Alembic throws an error like the head (&lt;strong&gt;b886dffa554d&lt;/strong&gt;) does not exist, or the requested revision was not found. This usually happens when the database has an old or incorrect revision stored in alembic_version.&lt;/p&gt;

&lt;p&gt;But our codebase (the alembic/versions directory) now uses a different head, such as &lt;strong&gt;26429623e713&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To fix the mismatch, we can manually update the revision stored in our database so it matches the latest head from our codebase.&lt;/p&gt;

&lt;p&gt;We can safely correct this using the following SQL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;UPDATE alembic_version
SET version_num = '26429623e713'
WHERE version_num = 'b886dffa554d';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To check the version&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SELECT * FROM alembic_version;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Scenario 2:&lt;/strong&gt;&lt;br&gt;
Suppose there are 2 developers, dev1 and dev2. They started working on two separate branches with 2 new features, corresponding to cloning the main branch. Suppose both made changes to their branch.&lt;/p&gt;

&lt;p&gt;In main branch: &lt;strong&gt;a-&amp;gt;b(head)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;dev1: &lt;strong&gt;a-&amp;gt;b-&amp;gt;d(head)&lt;/strong&gt;&lt;br&gt;
dev2: &lt;strong&gt;a-&amp;gt;b-&amp;gt;c(head)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While merging :&lt;/p&gt;

&lt;p&gt;dev1: &lt;strong&gt;a-&amp;gt;b-&amp;gt;d(head)&lt;/strong&gt; merged to main &lt;/p&gt;

&lt;p&gt;dev2: &lt;strong&gt;a-&amp;gt;b-&amp;gt;c(head)&lt;/strong&gt; [error: version d doesn’t exist]&lt;/p&gt;

&lt;p&gt;So, first we can rebase the dev1 branch now that the head is d. While adding dev2's feature, we can make the dev2's head, which is c, next to dev 1, which is d now. And push the changes to the dev1 branch. And then merge the dev1 PR. But this is sometimes problematic. Because we are rewriting migration history, which is sometimes dangerous.&lt;/p&gt;

&lt;p&gt;If migrations modify the same tables/columns, rebase may cause:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;inconsistent database states&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;duplicated constraints&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;partial schema drift&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Alembic does not support manually reordering migrations to resolve divergence.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, here is another solution:&lt;/p&gt;

&lt;p&gt;If dev1 merges first, the main branch becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a -&amp;gt; b -&amp;gt; d (head)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next pull the latest main into dev2’s branch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git checkout dev2
git pull origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now dev2 has both migrations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a -&amp;gt; b -&amp;gt; d (main)
a -&amp;gt; b -&amp;gt; c (dev2)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alembic will detect two heads: d, c.&lt;/p&gt;

&lt;p&gt;Run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alembic heads
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a merge migration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;alembic merge -m "Merge dev1 and dev2 migrations" d c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A new merge file is created. Now we can push it to dev2's branch and create a PR.&lt;/p&gt;

</description>
      <category>backend</category>
      <category>database</category>
      <category>tutorial</category>
      <category>python</category>
    </item>
    <item>
      <title>Understanding Asyncio and Multithreading in Python</title>
      <dc:creator>Shreshthajit das</dc:creator>
      <pubDate>Sun, 26 Oct 2025 05:42:02 +0000</pubDate>
      <link>https://forem.com/shreshthajit_das_1a7b40f5/understanding-asyncio-and-multithreading-in-python-663</link>
      <guid>https://forem.com/shreshthajit_das_1a7b40f5/understanding-asyncio-and-multithreading-in-python-663</guid>
      <description>&lt;p&gt;When we think about &lt;strong&gt;synchronous&lt;/strong&gt; program, it tells us that any task must finish before the next one starts. An &lt;strong&gt;asynchronous&lt;/strong&gt; program can toggle between tasks so that tasks can run concurrently without blocking each other.&lt;/p&gt;

&lt;p&gt;In Python, let's first try to understand the concepts of a coroutine and a subroutine. We are all familiar with a function, which is also known as a subroutine, procedure, sub-process, etc. A &lt;strong&gt;subroutine&lt;/strong&gt; is just a normal Python function defined with &lt;strong&gt;def&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;On the other hand, a &lt;strong&gt;coroutine&lt;/strong&gt; is something that is defined with &lt;strong&gt;async def&lt;/strong&gt; and can be paused with await or yield. A normal function in Python becomes a &lt;strong&gt;coroutine&lt;/strong&gt; when it is defined with the &lt;strong&gt;async def&lt;/strong&gt; syntax.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;async def&lt;/strong&gt; lets the current function temporarily pause its execution while the execution of respective (I/O, network requests, etc.) operations is in progress.&lt;/p&gt;

&lt;p&gt;It is important to note that &lt;strong&gt;coroutines&lt;/strong&gt; do not make the code multi-threaded; rather, coroutines run in an &lt;a href="https://docs.python.org/3/library/asyncio-eventloop.html" rel="noopener noreferrer"&gt;event loop&lt;/a&gt; that executes in a single thread. Upon the usage of &lt;strong&gt;async def&lt;/strong&gt;, the said function yields a coroutine object. When the await keyword is encountered, the current coroutine is paused, and control is passed back to the event loop.&lt;/p&gt;

&lt;p&gt;The CPU is less utilized (or might be free) when &lt;strong&gt;I/O&lt;/strong&gt; (or similar operations) are in progress. For instance, copying data to an external hard drive is an I/O operation where the CPU only initiates and accepts the I/O requests. The CPU can be better utilized in such cases for performing other tasks! The &lt;strong&gt;event loop&lt;/strong&gt; continuously monitors the awaitable (coroutine, Task, or Future) until it is completed. Once the execution of the awaitable or the newly picked-up task is complete, the event loop restores the execution of the paused coroutine.&lt;/p&gt;

&lt;p&gt;See the code below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import asyncio
import sys
import time
from datetime import datetime

async def task1():
   print("Enter " + sys._getframe().f_code.co_name + " " + str(datetime.now().time()))    # Get function name
   await asyncio.sleep(2)    # Could be an I/O operation, network request, database operation, and more
   ret_info = await task2()
   print("After sleep " + sys._getframe().f_code.co_name + " " + str(datetime.now().time()))
   return "task1"

async def task2():
   print("Enter " + sys._getframe().f_code.co_name + " " + str(datetime.now().time()))
   await asyncio.sleep(2)
   print("After sleep " + sys._getframe().f_code.co_name + " " + str(datetime.now().time()))
   return "task2"

async def main():
   print("Enter main")
   start_time = time.perf_counter()
   ret_info = await task1()
   print(f"Data received from the task1: {ret_info}" + " " + str(datetime.now().time()))
   ret_info = await task2()
   print(f"Data received from the task2: {ret_info}" + " " + str(datetime.now().time()))
   end_time = time.perf_counter()
   print("Exit main")
   print(f'It took {round(end_time - start_time,0)} second(s) to complete.')


if __name__ == '__main__':
   # main coroutine
   asyncio.run(main())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Enter main
Enter task1 10:27:58.983919
Enter task2 10:28:00.985972
After sleep task2 10:28:02.988581
After sleep task1 10:28:02.988645
Data received from the task1: task1 10:28:02.988658
Enter task2 10:28:02.988674
After sleep task2 10:28:04.991250
Data received from the task2: task2 10:28:04.991315
Exit main
It took 6.0 seconds to complete.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Here's the explanation&lt;/em&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;asyncio.run()&lt;/strong&gt; starts an event loop and runs the coroutine main().So execution enters the main() coroutine&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Prints "Enter main".start_time records the precise start time for measuring total duration.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Call and await task1()&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Control passes to task1().&lt;/li&gt;
&lt;li&gt;Because of await, main() is paused until task1() completes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Inside task1()&lt;/strong&gt;: Prints "Enter task1" along with the current time. asyncio.sleep(2) pauses task1 for 2 seconds asynchronously.&lt;br&gt;
During this time, other async tasks could run — but since main() is just waiting, nothing else does.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;After 2 seconds, task1 resumes&lt;/strong&gt;: Calls task2() and waits for it to complete.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Inside task2() (called from task1)&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prints entry message.&lt;/li&gt;
&lt;li&gt;Sleeps for another 2 seconds.&lt;/li&gt;
&lt;li&gt;Prints after-sleep message and returns "task2".&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Back to task1&lt;/strong&gt;: Once task2() finishes, task1() prints and returns      "task1".&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Back to main()&lt;/strong&gt;: Prints: "Data received from the task1: task1". Then it runs another: Calls and awaits task2() again (same as before: 2-second delay).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;After task2() returns&lt;/strong&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prints the result of task2.&lt;/li&gt;
&lt;li&gt;Ends program and prints total duration.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The task1() and task2() are defined as asynchronous functions (or coroutines). During the execution of task1(), an await keyword is encountered with an async sleep of 2 seconds. This pauses the coroutine and yields control back to the event loop.&lt;/p&gt;

&lt;p&gt;With this, the execution of task1() is paused until the completion of task2() coroutine. Post the execution of task2(), the execution of task1() coroutine is resumed, and the return value of task1 is printed on the terminal.&lt;/p&gt;

&lt;p&gt;To sum up, &lt;strong&gt;asyncio&lt;/strong&gt; is built on &lt;strong&gt;coroutines&lt;/strong&gt; managed by the event loop, with tasks scheduling them and futures holding results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multithreading
&lt;/h2&gt;

&lt;p&gt;Python achieves concurrency via context switching, which involves frequently switching between threads on single-core CPUs, giving the illusion of parallel execution or multitasking.&lt;/p&gt;

&lt;p&gt;Multiple threads facilitate the execution of background tasks without blocking the main program.&lt;/p&gt;

&lt;p&gt;Consider the diagram below to understand how multiple threads exist in memory:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F03gohd6g5h9pc3lyz0gk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F03gohd6g5h9pc3lyz0gk.png" alt="ThreadPic" width="721" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before moving ahead, it’s important to note that &lt;strong&gt;Python threading&lt;/strong&gt; is different from threading in other languages like Java, C#, or Go, where the threads can execute simultaneously on a multicore processor. Due to the design limitations of the Python interpreter(CPython), only one thread can run at a time.&lt;/p&gt;

&lt;p&gt;Actually, threads are managed by the &lt;a href="https://wiki.python.org/moin/GlobalInterpreterLock" rel="noopener noreferrer"&gt;Global Interpreter Lock (GIL)&lt;/a&gt;, which allows only one thread to execute Python bytecode at a time, even on multi-core systems.&lt;/p&gt;

&lt;p&gt;What’s really interesting is, threads in Python can coexist (run concurrently), and the interpreter switches between them rapidly (context switching).Example: Thread A runs a bit, then Thread B runs a bit, then back to A. But they cannot run at the exact same time on multiple cores (because the GIL allows only one to execute Python bytecode at once). So, threads are concurrent, not parallel, in CPU-bound tasks.&lt;/p&gt;

&lt;p&gt;To fully use multiple CPU cores in Python, use the multiprocessing module, which creates separate processes, each with its own GIL. Now each process runs independently, true parallelism.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F86siibz11tl3vew0wnr9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F86siibz11tl3vew0wnr9.png" alt="Threading in Python" width="731" height="791"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Here, we can create three threads that will independently download the three webpages concurrently and take varying amounts of time depending upon network conditions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The main thread will wait until all three threads have finished downloading since the join method of all the threads is set in the main thread.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once all three downloads are finished, the data is given to the create_single_webpage() function to create a single webpage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the join() method is not used, the main thread will immediately run the create_single_webpage() function before the downloads are finished and resulting in an error.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Advantages of Threading
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Threaded programs run faster on computer systems that have multiple CPUs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Threads of a process can share the memory of global variables. If the variable's value is changed in one thread, it is applicable to all threads.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the next part of this series, I’ll dive deeper into threads and how they differ from asyncio tasks.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>beginners</category>
      <category>python</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
