|
| https://realpython.com/ |
| Start Here | https://realpython.com/start-here/ |
|
Learn Python
| https://realpython.com/lessons/threads-in-python/ |
| Python Tutorials →In-depth articles and video courses | https://realpython.com/search?kind=article&kind=course&order=newest |
| Learning Paths →Guided study plans for accelerated learning | https://realpython.com/learning-paths/ |
| Quizzes & Exercises →Check your learning progress | https://realpython.com/quizzes/ |
| Browse Topics →Focus on a specific area or skill level | https://realpython.com/tutorials/all/ |
| Community Chat →Learn with other Pythonistas | https://realpython.com/community/ |
| Office Hours →Live Q&A calls with Python experts | https://realpython.com/office-hours/ |
| Podcast →Hear what’s new in the world of Python | https://realpython.com/podcasts/rpp/ |
| Books →Round out your knowledge and learn offline | https://realpython.com/products/books/ |
| Reference →Concise definitions for common Python terms | https://realpython.com/ref/ |
| Code Mentor →BetaPersonalized code assistance & learning tools | https://realpython.com/mentor/ |
| Unlock All Content → | https://realpython.com/account/join/ |
|
More
| https://realpython.com/lessons/threads-in-python/ |
| Learner Stories | https://realpython.com/learner-stories/ |
| Python Newsletter | https://realpython.com/newsletter/ |
| Python Job Board | https://www.pythonjobshq.com |
| Meet the Team | https://realpython.com/team/ |
| Become a Tutorial Writer | https://realpython.com/write-for-us/ |
| Become a Video Instructor | https://realpython.com/become-an-instructor/ |
| Search | https://realpython.com/search |
| https://realpython.com/search |
| Join | https://realpython.com/account/join/ |
| Sign‑In | https://realpython.com/account/login/?next=%2Flessons%2Fthreads-in-python%2F |
| Unlock This Lesson | https://realpython.com/account/join/?utm_source=rp_lesson&utm_content=speed-python-concurrency |
| Unlock This Lesson | https://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 Concurrency | https://realpython.com/courses/speed-python-concurrency/ |
| Christopher Trudeau | https://realpython.com/courses/speed-python-concurrency/#team |
| Recommended Tutorial | https://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 Question | https://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 |
| Transcript | https://realpython.com/lessons/threads-in-python/#transcript |
| Discussion (8) | https://realpython.com/lessons/threads-in-python/#discussion |
| 00:00 | https://realpython.com/lessons/threads-in-python/#t=0.545 |
| In the previous lesson, I introduced you to the concept | https://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:09 | https://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 input | https://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:18 | https://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:24 | https://realpython.com/lessons/threads-in-python/#t=24.685 |
| Threads work within the Python interpreter, and | https://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 a | https://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:37 | https://realpython.com/lessons/threads-in-python/#t=37.235 |
| All of the software that I demonstrate in this course is | https://realpython.com/lessons/threads-in-python/#t=37.235 |
| available in the supporting materials dropdown | https://realpython.com/lessons/threads-in-python/#t=39.735 |
| if you want to follow along. In order | https://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 synchronous | https://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:53 | https://realpython.com/lessons/threads-in-python/#t=53.275 |
| This program pulls down two different | https://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:58 | https://realpython.com/lessons/threads-in-python/#t=58.165 |
| Line 14 is | https://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 list | https://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:12 | https://realpython.com/lessons/threads-in-python/#t=72.285 |
| The download_site() function defined on line | https://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 using | https://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:24 | https://realpython.com/lessons/threads-in-python/#t=84.095 |
| In order to provide a little bit of clarity about | https://realpython.com/lessons/threads-in-python/#t=84.095 |
| what it’s doing, I’m printing out either a J | https://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 overkill | https://realpython.com/lessons/threads-in-python/#t=94.955 |
| in this case, you probably wouldn’t do it this way in | https://realpython.com/lessons/threads-in-python/#t=96.555 |
| reality, but it’s necessary for the threading library, so | https://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:45 | https://realpython.com/lessons/threads-in-python/#t=105.235 |
| Let me scroll down so that you can see | https://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:50 | https://realpython.com/lessons/threads-in-python/#t=110.805 |
| The list in line 21 is made up of 80 copies | https://realpython.com/lessons/threads-in-python/#t=110.805 |
| of the two different websites | https://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:02 | https://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 all | https://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:18 | https://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 site | https://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:33 | https://realpython.com/lessons/threads-in-python/#t=153.075 |
| This synchronous program is alternating | https://realpython.com/lessons/threads-in-python/#t=153.075 |
| between the two sites. | https://realpython.com/lessons/threads-in-python/#t=155.565 |
| 02:37 | https://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:43 | https://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 respond | https://realpython.com/lessons/threads-in-python/#t=168.545 |
| and how quickly the network interface on my computer | https://realpython.com/lessons/threads-in-python/#t=171.185 |
| decides to respond. | https://realpython.com/lessons/threads-in-python/#t=173.675 |
| 02:55 | https://realpython.com/lessons/threads-in-python/#t=175.795 |
| I’ve seen times for this program as much | https://realpython.com/lessons/threads-in-python/#t=175.795 |
| as triple this execution. | https://realpython.com/lessons/threads-in-python/#t=177.885 |
| 03:02 | https://realpython.com/lessons/threads-in-python/#t=182.255 |
| And now for a threaded version. First off, you’re going | https://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.futures | https://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:15 | https://realpython.com/lessons/threads-in-python/#t=195.315 |
| Line seven sets up the local environment | https://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:22 | https://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() has | https://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:33 | https://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:36 | https://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 has | https://realpython.com/lessons/threads-in-python/#t=221.805 |
| not been created before. | https://realpython.com/lessons/threads-in-python/#t=224.625 |
| 03:46 | https://realpython.com/lessons/threads-in-python/#t=226.745 |
| A combination of the use | https://realpython.com/lessons/threads-in-python/#t=226.745 |
| of the thread environment in line seven | https://realpython.com/lessons/threads-in-python/#t=227.985 |
| and the assignment of the requests session to | https://realpython.com/lessons/threads-in-python/#t=230.765 |
| that environment in line 11 allow you to change the number | https://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:00 | https://realpython.com/lessons/threads-in-python/#t=240.215 |
| This ensures that there’s only one request | https://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 library | https://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:15 | https://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 this | https://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() method | https://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:30 | https://realpython.com/lessons/threads-in-python/#t=270.635 |
| Each of the URLs in the sites listing gets mapped | https://realpython.com/lessons/threads-in-python/#t=270.635 |
| to a function, and the thread executor determines when | https://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 execution | https://realpython.com/lessons/threads-in-python/#t=280.515 |
| definition will change how many threads are active | https://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 data | https://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:59 | https://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:04 | https://realpython.com/lessons/threads-in-python/#t=304.275 |
| This is no different, so with some minor modifications | https://realpython.com/lessons/threads-in-python/#t=304.275 |
| to the script, I’ve changed it from being | https://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:18 | https://realpython.com/lessons/threads-in-python/#t=318.025 |
| Wow, that’s significantly faster than | https://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:38 | https://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 the | https://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:50 | https://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’s | https://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:01 | https://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 different | https://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 is | https://realpython.com/lessons/threads-in-python/#t=372.065 |
| going to be dependent on the network | https://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:21 | https://realpython.com/lessons/threads-in-python/#t=381.245 |
| The threaded version of the program was using the | https://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:27 | https://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 dictating | https://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:43 | https://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 as | https://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:02 | https://realpython.com/lessons/threads-in-python/#t=422.885 |
| The download_site() function is throwing out the data | https://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 onto | https://realpython.com/lessons/threads-in-python/#t=427.485 |
| the consumer. There’s just as a collection point | https://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:16 | https://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 with | https://realpython.com/lessons/threads-in-python/#t=440.215 |
| inside of threads. The thread library acts inside | https://realpython.com/lessons/threads-in-python/#t=443.065 |
| of the Python interpreter. | https://realpython.com/lessons/threads-in-python/#t=447.165 |
| 07:28 | https://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:33 | https://realpython.com/lessons/threads-in-python/#t=453.435 |
| Consider a case where there are two threads using a single | https://realpython.com/lessons/threads-in-python/#t=453.435 |
| request session | https://realpython.com/lessons/threads-in-python/#t=456.145 |
| object. Thread | https://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 first | https://realpython.com/lessons/threads-in-python/#t=466.745 |
| thread wasn’t finished. | https://realpython.com/lessons/threads-in-python/#t=468.945 |
| 07:50 | https://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:54 | https://realpython.com/lessons/threads-in-python/#t=474.515 |
| One solution to this is | https://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 resources | https://realpython.com/lessons/threads-in-python/#t=478.635 |
| and lock them so | https://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:04 | https://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 method | https://realpython.com/lessons/threads-in-python/#t=493.265 |
| that makes this easier. | https://realpython.com/lessons/threads-in-python/#t=496.105 |
| 08:17 | https://realpython.com/lessons/threads-in-python/#t=497.945 |
| This is the threading.local() method | https://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 space | https://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:32 | https://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 inside | https://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 session | https://realpython.com/lessons/threads-in-python/#t=519.635 |
| object, and also means that you don’t end up | https://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:52 | https://realpython.com/lessons/threads-in-python/#t=532.775 |
| In the example code I showed you, the max number | https://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:08 | https://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 all | https://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:20 | https://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 each | https://realpython.com/lessons/threads-in-python/#t=565.495 |
| of your threads are. | https://realpython.com/lessons/threads-in-python/#t=568.555 |
| 09:30 | https://realpython.com/lessons/threads-in-python/#t=570.215 |
| So you may want to experiment a little | https://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 there | https://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 ensures | https://realpython.com/lessons/threads-in-python/#t=580.255 |
| that the GUI is always responsive to the user | https://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:52 | https://realpython.com/lessons/threads-in-python/#t=592.025 |
| If you’re coming from another programming language | https://realpython.com/lessons/threads-in-python/#t=592.025 |
| or you’ve seen the Python threading mechanisms | https://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 typical | https://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:06 | https://realpython.com/lessons/threads-in-python/#t=606.915 |
| start is responsible for creating the threads | https://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 waits | https://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:15 | https://realpython.com/lessons/threads-in-python/#t=615.935 |
| And queue is a thread-safe mechanism for communicating | https://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 order | https://realpython.com/lessons/threads-in-python/#t=622.845 |
| to minimize the amount of code that you have | https://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:30 | https://realpython.com/lessons/threads-in-python/#t=630.665 |
| As you saw in the sample program, an executor is responsible | https://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 function | https://realpython.com/lessons/threads-in-python/#t=635.825 |
| and then maps those functions to the threads | https://realpython.com/lessons/threads-in-python/#t=638.145 |
| managing pools, abstracting away the complexities caused | https://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:46 | https://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 have | https://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.2 | https://realpython.com/lessons/threads-in-python/#t=654.415 |
| and later, you’re better off | https://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:00 | https://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 conditions | https://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, 2020 | https://realpython.com/lessons/threads-in-python/#comment-fdf844f4-5da7-4a73-8ac9-a05ce683bad2 |
| April 23, 2021 | https://realpython.com/lessons/threads-in-python/#comment-f947fada-452d-496d-9cda-f742e7a5946b |
| April 23, 2021 | https://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, 2023 | https://realpython.com/lessons/threads-in-python/#comment-a58ba806-5494-4eef-98a1-b3659b1fc837 |
| May 6, 2023 | https://realpython.com/lessons/threads-in-python/#comment-51c81258-7a04-47a6-86bc-adf307255647 |
| Feb. 6, 2024 | https://realpython.com/lessons/threads-in-python/#comment-e9a3fefd-b97b-4fec-90c5-548dd4b4bb38 |
| Feb. 6, 2024 | https://realpython.com/lessons/threads-in-python/#comment-6b6f739e-d5c5-4654-b036-5d4a26c309b4 |
| bypass the GIL | https://realpython.com/python-parallel-processing/ |
| Feb. 7, 2024 | https://realpython.com/lessons/threads-in-python/#comment-1d0d1b35-92bb-4170-9dd3-822a1d37e9e6 |
| Become a Member | https://realpython.com/account/join/ |
| https://realpython.com/videos/changes-challenges-concurrency/ |
| Overview | https://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 Policy | https://realpython.com/privacy-policy/ |
Viewport: width=device-width, initial-scale=1, shrink-to-fit=no, viewport-fit=cover