René's URL Explorer Experiment


Title: Threads in Python (Video) – Real Python

Open Graph Title: Threads in Python – Real Python

Description: In the previous lesson, I introduced you to the concept of concurrency and different patterns it can take. In this lesson, I’ll be talking about threads in Python, as I showed you in the lesson on latency. Most programs spend a lot of their time…

Open Graph Description: In the previous lesson, I introduced you to the concept of concurrency and different patterns it can take. In this lesson, I’ll be talking about threads in Python, as I showed you in the lesson on latency. Most programs spend a lot of their time…

Opengraph URL: https://realpython.com/lessons/threads-in-python/

X: @realpython

direct link

Domain: realpython.com


Hey, it has json ld scripts:
  {
    "@context": "https://schema.org",
    "@type": "VideoObject",
    "name": "Threads in Python",
    "description": "In the previous lesson, I introduced you to the concept of concurrency and different patterns it can take. In this lesson, I’ll be talking about threads in Python, as I showed you in the lesson on latency. Most programs spend a lot of their time…",
    "thumbnailUrl": ["https://files.realpython.com/media/An-Overview-of-Concurrency-in-Python_Watermarked.c54c399ccb32.jpg"],
    "uploadDate": "2025-10-28T14:00:00+00:00",
    "duration": "PT11M8S",
    
    "potentialAction": {
      "@type": "SeekToAction",
      "target": "https://realpython.com/lessons/threads-in-python/#t={seek_to_second_number}",
      "startOffset-input": "required name=seek_to_second_number"
    }
  }
  

authorReal Python
twitter:cardsummary_large_image
twitter:imagehttps://files.realpython.com/media/An-Overview-of-Concurrency-in-Python_Watermarked.c54c399ccb32.jpg
og:imagehttps://files.realpython.com/media/An-Overview-of-Concurrency-in-Python_Watermarked.c54c399ccb32.jpg
twitter:creator@realpython
og:typevideo.episode

Links:

https://realpython.com/
Start Herehttps://realpython.com/start-here/
Learn Python https://realpython.com/lessons/threads-in-python/
Python Tutorials →In-depth articles and video courseshttps://realpython.com/search?kind=article&kind=course&order=newest
Learning Paths →Guided study plans for accelerated learninghttps://realpython.com/learning-paths/
Quizzes & Exercises →Check your learning progresshttps://realpython.com/quizzes/
Browse Topics →Focus on a specific area or skill levelhttps://realpython.com/tutorials/all/
Community Chat →Learn with other Pythonistashttps://realpython.com/community/
Office Hours →Live Q&A calls with Python expertshttps://realpython.com/office-hours/
Podcast →Hear what’s new in the world of Pythonhttps://realpython.com/podcasts/rpp/
Books →Round out your knowledge and learn offlinehttps://realpython.com/products/books/
Reference →Concise definitions for common Python termshttps://realpython.com/ref/
Code Mentor →BetaPersonalized code assistance & learning toolshttps://realpython.com/mentor/
Unlock All Content →https://realpython.com/account/join/
More https://realpython.com/lessons/threads-in-python/
Learner Storieshttps://realpython.com/learner-stories/
Python Newsletterhttps://realpython.com/newsletter/
Python Job Boardhttps://www.pythonjobshq.com
Meet the Teamhttps://realpython.com/team/
Become a Tutorial Writerhttps://realpython.com/write-for-us/
Become a Video Instructorhttps://realpython.com/become-an-instructor/
Searchhttps://realpython.com/search
https://realpython.com/search
Joinhttps://realpython.com/account/join/
Sign‑Inhttps://realpython.com/account/login/?next=%2Flessons%2Fthreads-in-python%2F
Unlock This Lessonhttps://realpython.com/account/join/?utm_source=rp_lesson&utm_content=speed-python-concurrency
Unlock This Lessonhttps://realpython.com/account/join/?utm_source=rp_lesson&utm_content=speed-python-concurrency
https://realpython.com/courses/speed-python-concurrency/#team
Speed Up Python With Concurrencyhttps://realpython.com/courses/speed-python-concurrency/
Christopher Trudeauhttps://realpython.com/courses/speed-python-concurrency/#team
Recommended Tutorialhttps://realpython.com/python-concurrency/
Course Slides (.pdf)https://realpython.com/courses/speed-python-concurrency/downloads/concurrency-slides/
Sample Code (.zip)https://realpython.com/courses/speed-python-concurrency/downloads/concurrency-code/
Ask a Questionhttps://realpython.com/lessons/threads-in-python/#discussion
https://realpython.com/feedback/survey/course/speed-python-concurrency/liked/?from=lesson-title
https://realpython.com/feedback/survey/course/speed-python-concurrency/disliked/?from=lesson-title
Transcripthttps://realpython.com/lessons/threads-in-python/#transcript
Discussion (8)https://realpython.com/lessons/threads-in-python/#discussion
00:00https://realpython.com/lessons/threads-in-python/#t=0.545
In the previous lesson, I introduced you to the concepthttps://realpython.com/lessons/threads-in-python/#t=0.545
of concurrency and different patterns it can take.https://realpython.com/lessons/threads-in-python/#t=2.9050000000000002
In this lesson, I’ll be talking about threads in Python,https://realpython.com/lessons/threads-in-python/#t=5.865
00:09https://realpython.com/lessons/threads-in-python/#t=9.995
as I showed you in the lesson on latency.https://realpython.com/lessons/threads-in-python/#t=9.995
Most programs spend a lot of their time waiting for inputhttps://realpython.com/lessons/threads-in-python/#t=12.125
and output. Threads allow you to time slice your computation.https://realpython.com/lessons/threads-in-python/#t=14.815
00:18https://realpython.com/lessons/threads-in-python/#t=18.825
While one thread is waiting for input,https://realpython.com/lessons/threads-in-python/#t=18.825
another thread can continue to do processing work.https://realpython.com/lessons/threads-in-python/#t=21.005
00:24https://realpython.com/lessons/threads-in-python/#t=24.685
Threads work within the Python interpreter, andhttps://realpython.com/lessons/threads-in-python/#t=24.685
therefore, with the GIL.https://realpython.com/lessons/threads-in-python/#t=27.295
Significant speedup can be obtained if your software does ahttps://realpython.com/lessons/threads-in-python/#t=29.365
lot of disk or network activity.https://realpython.com/lessons/threads-in-python/#t=33.135
00:37https://realpython.com/lessons/threads-in-python/#t=37.235
All of the software that I demonstrate in this course ishttps://realpython.com/lessons/threads-in-python/#t=37.235
available in the supporting materials dropdownhttps://realpython.com/lessons/threads-in-python/#t=39.735
if you want to follow along. In orderhttps://realpython.com/lessons/threads-in-python/#t=42.355
to demonstrate the difference that threading can make,https://realpython.com/lessons/threads-in-python/#t=44.965
I need something to compare against,https://realpython.com/lessons/threads-in-python/#t=47.645
so I’m going to start with a synchronoushttps://realpython.com/lessons/threads-in-python/#t=49.465
version of a small program.https://realpython.com/lessons/threads-in-python/#t=51.285
00:53https://realpython.com/lessons/threads-in-python/#t=53.275
This program pulls down two differenthttps://realpython.com/lessons/threads-in-python/#t=53.275
web pages many, many times.https://realpython.com/lessons/threads-in-python/#t=55.085
00:58https://realpython.com/lessons/threads-in-python/#t=58.165
Line 14 ishttps://realpython.com/lessons/threads-in-python/#t=58.165
where you’ll find the key entry point to the code.https://realpython.com/lessons/threads-in-python/#t=59.295
This function called download_all_sites(), takes a listhttps://realpython.com/lessons/threads-in-python/#t=61.645
of sites, looks for each of the URLs in the list,https://realpython.com/lessons/threads-in-python/#t=64.615
and calls the download_site() function.https://realpython.com/lessons/threads-in-python/#t=68.795
01:12https://realpython.com/lessons/threads-in-python/#t=72.285
The download_site() function defined on linehttps://realpython.com/lessons/threads-in-python/#t=72.285
8 gets a session from requests,https://realpython.com/lessons/threads-in-python/#t=74.545
which is the library I’m usinghttps://realpython.com/lessons/threads-in-python/#t=77.675
to download web pages. On line 10,https://realpython.com/lessons/threads-in-python/#t=79.145
it fetches the content.https://realpython.com/lessons/threads-in-python/#t=82.075
01:24https://realpython.com/lessons/threads-in-python/#t=84.095
In order to provide a little bit of clarity abouthttps://realpython.com/lessons/threads-in-python/#t=84.095
what it’s doing, I’m printing out either a Jhttps://realpython.com/lessons/threads-in-python/#t=86.075
or an R depending on which website is being read.https://realpython.com/lessons/threads-in-python/#t=88.895
The definition of the get_session()https://realpython.com/lessons/threads-in-python/#t=92.775
function is a little bit overkillhttps://realpython.com/lessons/threads-in-python/#t=94.955
in this case, you probably wouldn’t do it this way inhttps://realpython.com/lessons/threads-in-python/#t=96.555
reality, but it’s necessary for the threading library, sohttps://realpython.com/lessons/threads-in-python/#t=98.915
to keep the code consistent, I’ve done it this way.https://realpython.com/lessons/threads-in-python/#t=101.835
01:45https://realpython.com/lessons/threads-in-python/#t=105.235
Let me scroll down so that you can seehttps://realpython.com/lessons/threads-in-python/#t=105.235
how this program is called.https://realpython.com/lessons/threads-in-python/#t=106.855
01:50https://realpython.com/lessons/threads-in-python/#t=110.805
The list in line 21 is made up of 80 copieshttps://realpython.com/lessons/threads-in-python/#t=110.805
of the two different websiteshttps://realpython.com/lessons/threads-in-python/#t=114.085
that the requests library is going to fetch.https://realpython.com/lessons/threads-in-python/#t=115.975
Line 26 tells you that it’s starting.https://realpython.com/lessons/threads-in-python/#t=119.415
02:02https://realpython.com/lessons/threads-in-python/#t=122.255
Line 27 starts a timer.https://realpython.com/lessons/threads-in-python/#t=122.255
Line 28 is the meat where it actually downloads allhttps://realpython.com/lessons/threads-in-python/#t=124.755
of the sites inside of the site’s list.https://realpython.com/lessons/threads-in-python/#t=128.005
Line 29 calculates how long it took for this to run,https://realpython.com/lessons/threads-in-python/#t=130.835
and then line 30 prints out some statistics.https://realpython.com/lessons/threads-in-python/#t=134.545
02:18https://realpython.com/lessons/threads-in-python/#t=138.615
Let’s see this program in action.https://realpython.com/lessons/threads-in-python/#t=138.615
There are 160 URLs being downloaded, 80 from Jthon,https://realpython.com/lessons/threads-in-python/#t=140.935
and 80 from Real Python.https://realpython.com/lessons/threads-in-python/#t=144.985
The j and r indicate when the Jthon sitehttps://realpython.com/lessons/threads-in-python/#t=147.105
or the Real Python site is being downloaded from.https://realpython.com/lessons/threads-in-python/#t=150.025
02:33https://realpython.com/lessons/threads-in-python/#t=153.075
This synchronous program is alternatinghttps://realpython.com/lessons/threads-in-python/#t=153.075
between the two sites.https://realpython.com/lessons/threads-in-python/#t=155.565
02:37https://realpython.com/lessons/threads-in-python/#t=157.875
The end result is 160 sites were run in about 14 seconds.https://realpython.com/lessons/threads-in-python/#t=157.875
02:43https://realpython.com/lessons/threads-in-python/#t=163.235
I’ve run this program several different times.https://realpython.com/lessons/threads-in-python/#t=163.235
The wait time for it varies wildly,https://realpython.com/lessons/threads-in-python/#t=165.705
and a lot of that depends on how quickly the sites respondhttps://realpython.com/lessons/threads-in-python/#t=168.545
and how quickly the network interface on my computerhttps://realpython.com/lessons/threads-in-python/#t=171.185
decides to respond.https://realpython.com/lessons/threads-in-python/#t=173.675
02:55https://realpython.com/lessons/threads-in-python/#t=175.795
I’ve seen times for this program as muchhttps://realpython.com/lessons/threads-in-python/#t=175.795
as triple this execution.https://realpython.com/lessons/threads-in-python/#t=177.885
03:02https://realpython.com/lessons/threads-in-python/#t=182.255
And now for a threaded version. First off, you’re goinghttps://realpython.com/lessons/threads-in-python/#t=182.255
to need two more imports.https://realpython.com/lessons/threads-in-python/#t=185.485
Both are part of the standard library.https://realpython.com/lessons/threads-in-python/#t=187.035
Line two introduces concurrent.futureshttps://realpython.com/lessons/threads-in-python/#t=189.375
and line four, the threading library.https://realpython.com/lessons/threads-in-python/#t=192.445
03:15https://realpython.com/lessons/threads-in-python/#t=195.315
Line seven sets up the local environmenthttps://realpython.com/lessons/threads-in-python/#t=195.315
for each of the threads.https://realpython.com/lessons/threads-in-python/#t=197.745
I’ll describe more of this later.https://realpython.com/lessons/threads-in-python/#t=199.635
03:22https://realpython.com/lessons/threads-in-python/#t=202.255
The download_site() method on line 15 hasn’t changed,https://realpython.com/lessons/threads-in-python/#t=202.255
it’s the same as before.https://realpython.com/lessons/threads-in-python/#t=205.625
But in order to use the threading library, get_session() hashttps://realpython.com/lessons/threads-in-python/#t=207.335
to be a little different.https://realpython.com/lessons/threads-in-python/#t=211.035
03:33https://realpython.com/lessons/threads-in-python/#t=213.135
Line nine defines the function get_session().https://realpython.com/lessons/threads-in-python/#t=213.135
03:36https://realpython.com/lessons/threads-in-python/#t=216.525
Inside of this function,https://realpython.com/lessons/threads-in-python/#t=216.525
line 11 gets the session from the requests library,https://realpython.com/lessons/threads-in-python/#t=217.695
but it only does this if thread_local hashttps://realpython.com/lessons/threads-in-python/#t=221.805
not been created before.https://realpython.com/lessons/threads-in-python/#t=224.625
03:46https://realpython.com/lessons/threads-in-python/#t=226.745
A combination of the usehttps://realpython.com/lessons/threads-in-python/#t=226.745
of the thread environment in line sevenhttps://realpython.com/lessons/threads-in-python/#t=227.985
and the assignment of the requests session tohttps://realpython.com/lessons/threads-in-python/#t=230.765
that environment in line 11 allow you to change the numberhttps://realpython.com/lessons/threads-in-python/#t=233.105
of threads in the program and not break anything.https://realpython.com/lessons/threads-in-python/#t=236.625
04:00https://realpython.com/lessons/threads-in-python/#t=240.215
This ensures that there’s only one requesthttps://realpython.com/lessons/threads-in-python/#t=240.215
session per thread.https://realpython.com/lessons/threads-in-python/#t=242.535
Now let’s see the download_all_sites() method.https://realpython.com/lessons/threads-in-python/#t=245.205
It’s changed a little. The concurrent.futures libraryhttps://realpython.com/lessons/threads-in-python/#t=247.575
includes a class called ThreadPoolExecutor.https://realpython.com/lessons/threads-in-python/#t=252.355
04:15https://realpython.com/lessons/threads-in-python/#t=255.865
This is what determines how many threads there are.https://realpython.com/lessons/threads-in-python/#t=255.865
You can instantiate thishttps://realpython.com/lessons/threads-in-python/#t=259.295
as a context manager using the with key statement,https://realpython.com/lessons/threads-in-python/#t=260.435
and then the executor has a map() methodhttps://realpython.com/lessons/threads-in-python/#t=263.855
mapping a function to some data.https://realpython.com/lessons/threads-in-python/#t=267.265
04:30https://realpython.com/lessons/threads-in-python/#t=270.635
Each of the URLs in the sites listing gets mappedhttps://realpython.com/lessons/threads-in-python/#t=270.635
to a function, and the thread executor determines whenhttps://realpython.com/lessons/threads-in-python/#t=273.685
that function is called for which thread.https://realpython.com/lessons/threads-in-python/#t=277.645
Varying the number of max_workers in the executionhttps://realpython.com/lessons/threads-in-python/#t=280.515
definition will change how many threads are activehttps://realpython.com/lessons/threads-in-python/#t=283.605
at the same time. As a function finishes,https://realpython.com/lessons/threads-in-python/#t=286.785
the thread will be put back into the pool,https://realpython.com/lessons/threads-in-python/#t=290.385
and the executor will then assign the next piece of datahttps://realpython.com/lessons/threads-in-python/#t=292.625
to the next available thread.https://realpython.com/lessons/threads-in-python/#t=296.625
04:59https://realpython.com/lessons/threads-in-python/#t=299.355
Let me scroll down to show you the calling.https://realpython.com/lessons/threads-in-python/#t=299.355
05:04https://realpython.com/lessons/threads-in-python/#t=304.275
This is no different, so with some minor modificationshttps://realpython.com/lessons/threads-in-python/#t=304.275
to the script, I’ve changed it from beinghttps://realpython.com/lessons/threads-in-python/#t=307.385
synchronous to threaded.https://realpython.com/lessons/threads-in-python/#t=309.965
Now, let me show you this in action.https://realpython.com/lessons/threads-in-python/#t=311.755
05:18https://realpython.com/lessons/threads-in-python/#t=318.025
Wow, that’s significantly faster thanhttps://realpython.com/lessons/threads-in-python/#t=318.025
before, almost 10 times. To be honest, this is kind of lucky.https://realpython.com/lessons/threads-in-python/#t=320.695
That’s one of the best times I’ve seen.https://realpython.com/lessons/threads-in-python/#t=324.395
Let me try it again just to show you.https://realpython.com/lessons/threads-in-python/#t=326.715
05:38https://realpython.com/lessons/threads-in-python/#t=338.435
Not as good this time.https://realpython.com/lessons/threads-in-python/#t=338.435
Seven and a half seconds is still impressive though.https://realpython.com/lessons/threads-in-python/#t=339.425
That’s almost doubling thehttps://realpython.com/lessons/threads-in-python/#t=342.115
execution from the synchronous program.https://realpython.com/lessons/threads-in-python/#t=343.335
One thing to notice here is the patterns of the J’s and R’s.https://realpython.com/lessons/threads-in-python/#t=345.715
05:50https://realpython.com/lessons/threads-in-python/#t=350.195
In the synchronous program, it was always J,https://realpython.com/lessons/threads-in-python/#t=350.195
then R, J, then R.https://realpython.com/lessons/threads-in-python/#t=353.095
In this program, it isn’t, and that’shttps://realpython.com/lessons/threads-in-python/#t=355.315
because the threads are waiting different amounts of time.https://realpython.com/lessons/threads-in-python/#t=358.045
06:01https://realpython.com/lessons/threads-in-python/#t=361.825
As Jthon or Real Python is more or less responsive,https://realpython.com/lessons/threads-in-python/#t=361.825
the threads are executing at differenthttps://realpython.com/lessons/threads-in-python/#t=365.625
rates. At any given time,https://realpython.com/lessons/threads-in-python/#t=367.365
the executor makes sure that only five of them are running,https://realpython.com/lessons/threads-in-python/#t=369.425
but the order that the download_site() function finishes in ishttps://realpython.com/lessons/threads-in-python/#t=372.065
going to be dependent on the networkhttps://realpython.com/lessons/threads-in-python/#t=375.565
and the server on the other end.https://realpython.com/lessons/threads-in-python/#t=377.425
06:21https://realpython.com/lessons/threads-in-python/#t=381.245
The threaded version of the program was using thehttps://realpython.com/lessons/threads-in-python/#t=381.245
N-workers pattern that I introduced in the previous lesson.https://realpython.com/lessons/threads-in-python/#t=383.745
06:27https://realpython.com/lessons/threads-in-python/#t=387.465
download_all_sites() is the producer.https://realpython.com/lessons/threads-in-python/#t=387.465
It is what manages the list of sites that need to be done.https://realpython.com/lessons/threads-in-python/#t=390.085
That download_site() function acts as the worker,https://realpython.com/lessons/threads-in-python/#t=394.285
and in this case, concurrent.futures is dictatinghttps://realpython.com/lessons/threads-in-python/#t=397.595
that there are five workers.https://realpython.com/lessons/threads-in-python/#t=401.095
06:43https://realpython.com/lessons/threads-in-python/#t=403.435
And then finally, the executor acts as a collection point.https://realpython.com/lessons/threads-in-python/#t=403.435
It waits until all of the threads are finished,https://realpython.com/lessons/threads-in-python/#t=406.755
and once they are, the program continues ashttps://realpython.com/lessons/threads-in-python/#t=409.275
before, once the pool passes execution on. In this case,https://realpython.com/lessons/threads-in-python/#t=411.815
the print downloaded gets called. To be picky about it,https://realpython.com/lessons/threads-in-python/#t=416.395
this program technically doesn’t have a consumer.https://realpython.com/lessons/threads-in-python/#t=420.215
07:02https://realpython.com/lessons/threads-in-python/#t=422.885
The download_site() function is throwing out the datahttps://realpython.com/lessons/threads-in-python/#t=422.885
and not really doing any computation,https://realpython.com/lessons/threads-in-python/#t=425.645
so there was nothing to be passed ontohttps://realpython.com/lessons/threads-in-python/#t=427.485
the consumer. There’s just as a collection pointhttps://realpython.com/lessons/threads-in-python/#t=428.965
where the synchronous program resumes.https://realpython.com/lessons/threads-in-python/#t=431.875
07:16https://realpython.com/lessons/threads-in-python/#t=436.025
In the previous lesson, when I described the GIL for you,https://realpython.com/lessons/threads-in-python/#t=436.025
I mentioned race conditions.https://realpython.com/lessons/threads-in-python/#t=438.485
These are something that you have to be very careful withhttps://realpython.com/lessons/threads-in-python/#t=440.215
inside of threads. The thread library acts insidehttps://realpython.com/lessons/threads-in-python/#t=443.065
of the Python interpreter.https://realpython.com/lessons/threads-in-python/#t=447.165
07:28https://realpython.com/lessons/threads-in-python/#t=448.825
All of the memory is shared across all of the threads.https://realpython.com/lessons/threads-in-python/#t=448.825
07:33https://realpython.com/lessons/threads-in-python/#t=453.435
Consider a case where there are two threads using a singlehttps://realpython.com/lessons/threads-in-python/#t=453.435
request sessionhttps://realpython.com/lessons/threads-in-python/#t=456.145
object. Threadhttps://realpython.com/lessons/threads-in-python/#t=457.455
1 starts downloading from Jython, but then gets interrupted.https://realpython.com/lessons/threads-in-python/#t=459.265
Thread 2 then starts downloading from Real Python,https://realpython.com/lessons/threads-in-python/#t=463.665
but the session object from the firsthttps://realpython.com/lessons/threads-in-python/#t=466.745
thread wasn’t finished.https://realpython.com/lessons/threads-in-python/#t=468.945
07:50https://realpython.com/lessons/threads-in-python/#t=470.755
This is going to cause the requests library to fail.https://realpython.com/lessons/threads-in-python/#t=470.755
07:54https://realpython.com/lessons/threads-in-python/#t=474.515
One solution to this ishttps://realpython.com/lessons/threads-in-python/#t=474.515
to use a low-level mechanism called locking.https://realpython.com/lessons/threads-in-python/#t=475.735
You manage your resourceshttps://realpython.com/lessons/threads-in-python/#t=478.635
and lock them sohttps://realpython.com/lessons/threads-in-python/#t=480.195
that only one thread can use a resource at a time.https://realpython.com/lessons/threads-in-python/#t=481.215
08:04https://realpython.com/lessons/threads-in-python/#t=484.565
This kind of locking is exactly what the GIL is for,https://realpython.com/lessons/threads-in-python/#t=484.565
but it’s at the global level inside of the interpreter.https://realpython.com/lessons/threads-in-python/#t=487.595
Your code has the same problem.https://realpython.com/lessons/threads-in-python/#t=490.845
Fortunately, Python comes with a library methodhttps://realpython.com/lessons/threads-in-python/#t=493.265
that makes this easier.https://realpython.com/lessons/threads-in-python/#t=496.105
08:17https://realpython.com/lessons/threads-in-python/#t=497.945
This is the threading.local() methodhttps://realpython.com/lessons/threads-in-python/#t=497.945
that you saw on line seven of the code.https://realpython.com/lessons/threads-in-python/#t=499.515
It looks like a global variable, but it isn’t.https://realpython.com/lessons/threads-in-python/#t=502.665
The threading library is creating a locked spacehttps://realpython.com/lessons/threads-in-python/#t=505.185
for your objects that are created once per thread.https://realpython.com/lessons/threads-in-python/#t=508.505
08:32https://realpython.com/lessons/threads-in-python/#t=512.625
In the get_session() method,https://realpython.com/lessons/threads-in-python/#t=512.625
a new request session object was created insidehttps://realpython.com/lessons/threads-in-python/#t=514.405
of this threading local space.https://realpython.com/lessons/threads-in-python/#t=517.405
This guaranteed that each thread got its own request sessionhttps://realpython.com/lessons/threads-in-python/#t=519.635
object, and also means that you don’t end uphttps://realpython.com/lessons/threads-in-python/#t=523.105
with 160 request session objects for your 160 URLs.https://realpython.com/lessons/threads-in-python/#t=526.205
08:52https://realpython.com/lessons/threads-in-python/#t=532.775
In the example code I showed you, the max numberhttps://realpython.com/lessons/threads-in-python/#t=532.775
of workers was set to five.https://realpython.com/lessons/threads-in-python/#t=535.085
There were only five threads happening at a time.https://realpython.com/lessons/threads-in-python/#t=536.895
This was done on purpose.https://realpython.com/lessons/threads-in-python/#t=540.395
Although you’re downloading 160 URLs,https://realpython.com/lessons/threads-in-python/#t=542.525
you probably don’t want 160 threads.https://realpython.com/lessons/threads-in-python/#t=545.185
09:08https://realpython.com/lessons/threads-in-python/#t=548.235
There’s overhead for creating threads.https://realpython.com/lessons/threads-in-python/#t=548.235
There’s also overhead for switching between the threads.https://realpython.com/lessons/threads-in-python/#t=550.975
If you have too many threads,https://realpython.com/lessons/threads-in-python/#t=555.255
that means your code spends allhttps://realpython.com/lessons/threads-in-python/#t=556.705
of its time managing the threads.https://realpython.com/lessons/threads-in-python/#t=558.435
09:20https://realpython.com/lessons/threads-in-python/#t=560.935
So how do you know how many threads to have?https://realpython.com/lessons/threads-in-python/#t=560.935
Well, unfortunately, it’s not an easy answer,https://realpython.com/lessons/threads-in-python/#t=562.985
and it’s going to be dependent on how IO-bound eachhttps://realpython.com/lessons/threads-in-python/#t=565.495
of your threads are.https://realpython.com/lessons/threads-in-python/#t=568.555
09:30https://realpython.com/lessons/threads-in-python/#t=570.215
So you may want to experiment a littlehttps://realpython.com/lessons/threads-in-python/#t=570.215
bit based on your program.https://realpython.com/lessons/threads-in-python/#t=572.195
An extremely common pattern in GUI software is for therehttps://realpython.com/lessons/threads-in-python/#t=574.415
to be a thread for the GUI itself,https://realpython.com/lessons/threads-in-python/#t=577.835
and another thread for execution in behind. This ensureshttps://realpython.com/lessons/threads-in-python/#t=580.255
that the GUI is always responsive to the userhttps://realpython.com/lessons/threads-in-python/#t=584.035
and any expensive computation is done on a separate thread.https://realpython.com/lessons/threads-in-python/#t=586.775
09:52https://realpython.com/lessons/threads-in-python/#t=592.025
If you’re coming from another programming languagehttps://realpython.com/lessons/threads-in-python/#t=592.025
or you’ve seen the Python threading mechanismshttps://realpython.com/lessons/threads-in-python/#t=594.145
before, you might be wondering about the primitives.https://realpython.com/lessons/threads-in-python/#t=596.205
The Python threading library also supports the typicalhttps://realpython.com/lessons/threads-in-python/#t=599.695
thread primitives: start, join, and queue.https://realpython.com/lessons/threads-in-python/#t=602.355
10:06https://realpython.com/lessons/threads-in-python/#t=606.915
start is responsible for creating the threadshttps://realpython.com/lessons/threads-in-python/#t=606.915
and calling the appropriate functions.https://realpython.com/lessons/threads-in-python/#t=609.405
join is the point in the program that waitshttps://realpython.com/lessons/threads-in-python/#t=611.945
for all the threads to finish.https://realpython.com/lessons/threads-in-python/#t=613.995
10:15https://realpython.com/lessons/threads-in-python/#t=615.935
And queue is a thread-safe mechanism for communicatinghttps://realpython.com/lessons/threads-in-python/#t=615.935
between threads.https://realpython.com/lessons/threads-in-python/#t=619.075
Python has these primitives,https://realpython.com/lessons/threads-in-python/#t=621.045
but introduced the concurrent.futures library in orderhttps://realpython.com/lessons/threads-in-python/#t=622.845
to minimize the amount of code that you havehttps://realpython.com/lessons/threads-in-python/#t=625.625
to write when managing threads.https://realpython.com/lessons/threads-in-python/#t=627.345
10:30https://realpython.com/lessons/threads-in-python/#t=630.665
As you saw in the sample program, an executor is responsiblehttps://realpython.com/lessons/threads-in-python/#t=630.665
for managing threads.https://realpython.com/lessons/threads-in-python/#t=634.005
It maps data to a functionhttps://realpython.com/lessons/threads-in-python/#t=635.825
and then maps those functions to the threadshttps://realpython.com/lessons/threads-in-python/#t=638.145
managing pools, abstracting away the complexities causedhttps://realpython.com/lessons/threads-in-python/#t=641.045
by start, join, and queue.https://realpython.com/lessons/threads-in-python/#t=644.225
10:46https://realpython.com/lessons/threads-in-python/#t=646.905
This library was first introduced in Python 3.2,https://realpython.com/lessons/threads-in-python/#t=646.905
so if you’re using something older than that, you’ll havehttps://realpython.com/lessons/threads-in-python/#t=650.295
to stick with the basic primitives.https://realpython.com/lessons/threads-in-python/#t=652.475
But if you’re using 3.2https://realpython.com/lessons/threads-in-python/#t=654.415
and later, you’re better offhttps://realpython.com/lessons/threads-in-python/#t=655.655
looking at the futures library.https://realpython.com/lessons/threads-in-python/#t=657.235
11:00https://realpython.com/lessons/threads-in-python/#t=660.585
So that’s threading in Python.https://realpython.com/lessons/threads-in-python/#t=660.585
Next up, I’m going to show you what can cause race conditionshttps://realpython.com/lessons/threads-in-python/#t=662.315
and how they’re problematic.https://realpython.com/lessons/threads-in-python/#t=665.185
Dec. 25, 2020https://realpython.com/lessons/threads-in-python/#comment-fdf844f4-5da7-4a73-8ac9-a05ce683bad2
April 23, 2021https://realpython.com/lessons/threads-in-python/#comment-f947fada-452d-496d-9cda-f742e7a5946b
April 23, 2021https://realpython.com/lessons/threads-in-python/#comment-80432851-cd55-4a3d-aeca-1791c9f04901
realpython.com/intro-to-python-threading/https://realpython.com/intro-to-python-threading/
May 5, 2023https://realpython.com/lessons/threads-in-python/#comment-a58ba806-5494-4eef-98a1-b3659b1fc837
May 6, 2023https://realpython.com/lessons/threads-in-python/#comment-51c81258-7a04-47a6-86bc-adf307255647
Feb. 6, 2024https://realpython.com/lessons/threads-in-python/#comment-e9a3fefd-b97b-4fec-90c5-548dd4b4bb38
Feb. 6, 2024https://realpython.com/lessons/threads-in-python/#comment-6b6f739e-d5c5-4654-b036-5d4a26c309b4
bypass the GILhttps://realpython.com/python-parallel-processing/
Feb. 7, 2024https://realpython.com/lessons/threads-in-python/#comment-1d0d1b35-92bb-4170-9dd3-822a1d37e9e6
Become a Memberhttps://realpython.com/account/join/
https://realpython.com/videos/changes-challenges-concurrency/
Overviewhttps://realpython.com/courses/speed-python-concurrency/
https://realpython.com/lessons/concurreny-race-conditions/
Speed Up Python With Concurrency (Overview) 03:49 https://realpython.com/videos/python-concurrency-overview/
Computers and Latency 07:39 https://realpython.com/videos/computers-latency/
Taking Advantage of Latency With Concurrency Patterns 07:31 https://realpython.com/videos/concurrency/
Exploring Changes & Challenges With Concurrency 05:59 https://realpython.com/videos/changes-challenges-concurrency/
Threads in Python 11:08 https://realpython.com/lessons/threads-in-python/
Demonstrating Race Conditions 06:32 https://realpython.com/lessons/concurreny-race-conditions/
Understanding That the GIL Won't Save You 03:58 https://realpython.com/lessons/gil-wont-save-you/
Introducing asyncio 09:19 https://realpython.com/lessons/asyncio-version/
Multi-processing Version 06:44 https://realpython.com/lessons/multi-processing-version/
Differentiating Between IO Bound & CPU Bound 07:47 https://realpython.com/lessons/cpu-bound-workloads/
Python Concurrency (Quiz) 05:30 https://realpython.com/lessons/python-concurrency-quiz/
Speed Up Python With Concurrency (Summary) 05:36 https://realpython.com/lessons/python-concurrency-summary/
Privacy Policyhttps://realpython.com/privacy-policy/

Viewport: width=device-width, initial-scale=1, shrink-to-fit=no, viewport-fit=cover

Robots: max-image-preview:large


URLs of crawlers that visited me.