Python Threading: The Truth About GIL
46sReveals the surprising fact that Python doesn't have true multi-threading due to the GIL, sparking curiosity and debate.
▶ Play ClipThis video explains multi-threading in Python using the `threading` module. It clarifies that due to the Global Interpreter Lock (GIL), Python's threading is pseudo-concurrent, switching between tasks during I/O waits. The tutorial demonstrates creating and managing threads with a simple worker function that prints a counter until a user quits.
The video covers multi-threading in Python simply and quickly.
Due to the Global Interpreter Lock (GIL), Python uses pseudo multi-threading, switching between tasks during downtime (e.g., waiting for I/O, user input, or sleep).
Use `import threading` (core module) and `import time` for the `sleep` function to create downtime.
A `worker` function is defined with a loop that increments a counter and prints it every second, controlled by a global `done` flag.
Running the worker function in the main thread blocks execution, preventing user input handling until the loop ends.
Use `threading.Thread(target=worker).start()` to run the worker function in a separate thread, allowing simultaneous user input.
Set `daemon=True` to make a thread a daemon thread, which allows the script to exit even if the thread is still running, as it runs in the background.
Use `args=(value,)` to pass arguments to the target function. Multiple threads can run the same function with different arguments.
Use `thread.join()` to wait for a thread to finish before continuing execution in the main thread.
Python's threading module enables concurrent execution by switching tasks during I/O waits, but true parallelism is limited by the GIL. The tutorial provides a practical example of creating, starting, and managing threads, including daemon threads and joining.
"The title promises a quick explanation of Python threading in 8 minutes, and the video delivers a concise, practical tutorial that covers the core concepts."
What is the Global Interpreter Lock (GIL) in CPython?
The GIL prevents true multi-threading by allowing only one thread to execute Python bytecode at a time, leading to pseudo-concurrency.
0:16
How do you create and start a thread in Python?
Use `threading.Thread(target=function_name).start()`.
3:41
What is a daemon thread?
A daemon thread runs in the background and does not prevent the program from exiting when only daemon threads remain.
4:53
How do you pass arguments to a thread's target function?
Use the `args` parameter with a tuple, e.g., `threading.Thread(target=func, args=(value,))`.
5:36
What does the `join()` method do on a thread object?
It blocks the calling thread until the thread whose `join()` was called finishes execution.
7:22
What is the purpose of `time.sleep()` in the threading example?
It simulates downtime (I/O wait) that allows the GIL to switch between threads.
1:56
No True Multi-threading in CPython
Clarifies a common misconception about Python threading due to the GIL.
0:16Creating a Thread with threading.Thread
Demonstrates the core syntax for spawning a thread.
3:41Daemon Threads Allow Script Exit
Explains how daemon threads enable clean program termination.
4:53Joining Threads for Synchronization
Shows how to wait for thread completion before proceeding.
7:22[00:00] what is going on guys welcome back in
[00:01] this video today we're going to cover
[00:03] multi-threading in python as simply and
[00:05] as quickly as possible so let us get
[00:07] right into it it's not a g it's
[00:12] [Music]
[00:16] AED all right now one thing that I want
[00:18] to mention right away is that there is
[00:20] no actual multi-threading in Python at
[00:22] least not in the most commonly used
[00:24] cpython implementation that you're
[00:25] probably running on your system because
[00:28] of something called the global interpret
[00:30] to lock and we're not going to go into
[00:31] too much detail here but what this
[00:33] essentially means is that we have some
[00:35] sort of pseudo multi-threading where we
[00:37] do stuff concurrently and somewhat at
[00:39] the same time but what's actually
[00:41] happening is that we're switching
[00:43] between the tasks and we're using the
[00:44] down times of the different tasks to
[00:46] execute the other tasks so for example
[00:48] we send a request we wait for a response
[00:51] that is some doubt time or we're waiting
[00:52] for user input that is some downtime or
[00:55] we're just sleeping with time dos sleep
[00:57] that is also some downtime and this can
[00:58] be used for execution of other tasks and
[01:01] this is what the threading module
[01:02] actually does and this is just the
[01:04] theoretical background here in order to
[01:06] work with multi-threading and python
[01:08] with the pseudo multi-threading in
[01:10] Python what you need to do is you need
[01:11] to say import threading uh this is a
[01:14] core python module we don't need to
[01:15] install anything for that uh and in
[01:18] addition to that we're going to also
[01:19] import time which is going to allow us
[01:21] to use the mentioned sleep function to
[01:23] create some downtime and we're going to
[01:26] do a very simple example here to
[01:27] understand the concept of threading in
[01:29] python or for multi-threading in Python
[01:31] what we're going to do is we're going to
[01:32] define a function we're going to call it
[01:34] worker because it's going to be our
[01:36] worker function and this function will
[01:38] do something quite simple we're going to
[01:40] Define a variable up here done we're
[01:42] going to set it to false and inside of
[01:45] our worker function we're going to have
[01:47] a loop while not done so basically an
[01:49] endless loop until this thing is set to
[01:52] True while not done we're going to say
[01:56] uh time do sleep wait 1 second sleep 1
[02:00] second basically and then we're going to
[02:03] print some counter we're going to first
[02:06] of all Define a counter up here being
[02:08] equal to zero we're going to say that
[02:11] the counter is going to be increased by
[02:12] one with each
[02:14] iteration and we're going to print the
[02:16] counter this is what we want to do here
[02:18] nothing too fancy just a simple function
[02:20] that constantly prints 1 2 3 4 until we
[02:24] set done to true so without using any
[02:27] threading stuff here let's just run this
[02:29] function and see what happens this is
[02:31] going to be then running in the main
[02:32] thread and you can see it just prints 1
[02:34] 2 3 4 5 and so on um now what we want to
[02:39] do here is we want to in addition to
[02:41] that function also process some user
[02:43] input so in the main thread for example
[02:45] we want to wait for the user to input
[02:47] something or to just press enter now how
[02:50] would we do that we would do something
[02:52] like while not
[02:53] done we want to say uh wait for the user
[02:57] input so press PR enter to quit for
[03:02] example or actually we don't need to
[03:04] Loop here we can just wait for the input
[03:05] statement here and after the input
[03:07] statement is over so after the user
[03:09] presses uh enter we can just set done to
[03:12] true so the goal is to have this
[03:14] function running counting from uh 1 to
[03:17] two to three to four and so on until we
[03:19] press enter to quit that the problem is
[03:22] however now that um this is running in
[03:25] the main thread and this comes after dys
[03:28] function so we will not get to that
[03:29] statement uh unless this function
[03:32] finishes with the work so unless this
[03:34] function breaks out of the loop and we
[03:35] can continue with the rest of the code
[03:37] if we want to have both things running
[03:39] simultaneously we will have to do
[03:41] multi-threading and this is done the
[03:43] following way we used the threading
[03:44] module to define a thread by saying
[03:46] threading do thread and then we can
[03:49] specify a Target function so Target
[03:51] equals and we can pass the worker
[03:53] function here as an object passing it as
[03:56] an object means not passing it with the
[03:57] parenthesis so not calling it but just
[04:00] uh passing the instance of worker just
[04:03] passing the object worker which is the
[04:05] function The Entity worker um and then
[04:09] this is the object this is the actual
[04:10] threat we can either store it in a
[04:12] variable and then start the variable or
[04:13] we can start it right away like this by
[04:16] setting saying threading do thread
[04:18] Target equals worker. start and this is
[04:20] going to now start the worker function
[04:22] in a separate thread so if I run this um
[04:25] you will be able to see press enter to
[04:27] quit 1 2 3 I'm not pressing anything if
[04:29] I now press enter it goes past the
[04:32] statement and it sets done to true and
[04:34] since done is set to true this also
[04:36] terminates this worker now this would
[04:39] not work of course if I have here an
[04:41] endless loop while true then even if I
[04:44] press enter it's not going to quit
[04:46] because then uh the main thread doesn't
[04:48] have anything to do but this threat is
[04:50] still running however we can also change
[04:53] that by saying that this threat is not
[04:55] an important threat we don't want to
[04:57] keep the program running if everything
[04:59] else has finished finished this is a
[05:00] so-called Damon threat which basically
[05:02] means if nothing else is running you can
[05:04] also quit the script even though this
[05:06] threat is running we can specify here
[05:08] Damon equals true and this basically
[05:11] means what I just said that this is
[05:12] running in the background and as soon as
[05:15] the main threat and the other important
[05:16] threats have finished we can also quit
[05:19] the script we don't have to wait for
[05:20] this particular threat here because it's
[05:23] just a Damon threat so I can run this
[05:24] now and I can press enter And even
[05:27] though this enter doesn't change
[05:29] anything about this Loop even though
[05:30] this threat is still running we're just
[05:32] terminating the whole script because
[05:33] this is just a Damon threat that is what
[05:36] this is for we can also pass arguments
[05:38] by just passing text here for example
[05:41] and saying that we want to print an F
[05:44] string with text and then the counter
[05:47] just making up some stuff here uh we can
[05:50] do that by passing arguments so we can
[05:52] say arcs equals and we can pass a tupal
[05:55] of arguments here and in this case we're
[05:56] going to just pass ABC but since this is
[05:58] a tupal we need need to also pass a
[06:00] comma otherwise this is just going to be
[06:02] treated as a single value but we need a
[06:04] tuple uh we can do the same thing we can
[06:06] run another thread with the same
[06:08] function XYZ here as a text and you're
[06:11] going to see what this actually does you
[06:14] can see that it uh prints ABC counter oh
[06:17] actually I just noticed that we're uh
[06:19] printing counter we need of course to
[06:21] print the actual value of counter you
[06:25] can see here now abc1 xyz1 uh how these
[06:28] are running in parallel and if I press
[06:30] enter since both of them are Damon
[06:32] threats we are quitting the script if I
[06:34] set now one of them not to a Damon
[06:36] threat and the other one uh to a Damon
[06:38] threat uh you will see that if I just
[06:40] press enter now one of them is going to
[06:42] stop um
[06:45] actually doesn't stop any of those oh of
[06:48] course sorry this was uh this was not a
[06:50] correct thought because since one of
[06:52] them is running the other one is going
[06:53] to run as well because if we set one of
[06:56] them to not a Damon thread this is still
[06:58] an important thread and because the
[07:00] script is not finished because there is
[07:02] some threat still running the Damon
[07:03] threat is going to run as well um so
[07:06] setting one of them to false to not
[07:09] being a Damon threat keeps all of them
[07:10] running because Damon doesn't mean that
[07:12] you're just quitting it but it just
[07:14] means that since something is still
[07:16] running we're going to keep this running
[07:18] as well but if nothing else is running
[07:19] we're going to uh not keep this running
[07:22] anymore and the last thing I want to
[07:24] show you here I'm not going to show you
[07:25] here as a demonstration but just as a
[07:27] concept is if you have a list of mult
[07:29] multiple threats if you say for example
[07:31] this is T1 and this is T2 and you don't
[07:34] call the start but you just save them as
[07:36] objects here and then you do T1 start
[07:39] and T2 start this is the same
[07:41] functionality here you can also wait for
[07:43] those threats so if you do something and
[07:45] you don't want to continue with this
[07:47] here until both threats have finished
[07:49] with the execution then you can say t1.
[07:52] jooin and t2. jooin and you would not
[07:55] get to this code section here um until
[07:58] the threats have finished so you can see
[07:59] it doesn't even print press enter to
[08:01] quit because it doesn't get to that line
[08:03] since both threats are still running so
[08:06] that's it for today's video I hope you
[08:07] enjoyed it and hope you learned
[08:09] something if so let me know by hitting a
[08:10] like button and leaving a comment in the
[08:12] comment section down below and of course
[08:13] don't forget to subscribe to this
[08:14] Channel and hit the notification Bell to
[08:16] not miss a single future video for free
[08:18] other than that thank you much for
[08:19] watching see you in the next video and
[08:21] bye
[08:35] [Music]
⚡ Saved you time reading this? Transcribe any YouTube video for free — no signup needed.