Locked learning resources

Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Locked learning resources

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

When to Use concurrent.futures or multiprocessing

In this lesson, you’ll see which situations might be better suited to using either concurrent.futures or multiprocessing. You’ll also learn about how that ties in with the Global Interpreter Lock (GIL).

Because of the GIL, no two threads can execute Python code at the same time. So even if you have multiple threads running in your Python program, only one of them can execute at a time. The best way to get around this is to use process-based parallel programing, or process-based parallelism.

00:00 Now, of course, the question is, “Well, when should you use one over the other?” The dark secret of Python is something called the Global Interpreter Lock.

00:10 What it means, basically, is that no two threads can execute Python code at the same time. Even if you have multiple threads running in your Python program, only one of them can execute at a time. Now, this sounds like a huge limitation and in some cases it is, but, really, what happens most of the time is that your thread will be waiting on I/O to complete. In this case, if I’m calling time.sleep()that’s an I/O operation. That’s blocking this thread. That means while that time.sleep() call is blocking this one thread, other threads can execute, and then at the end, the thread will resume and they will all finish their processing.

00:52 So in this case, it doesn’t really make a difference. However, if I was doing heavy number crunching in these threads, I would run into the global interpreter lock problem because the end result wouldn’t really be faster than running a single-threaded version.

01:06 So, there’s lots more to say about this, but really what you need to remember is that the best way to get around this is to use process-based parallel programming in Python, or process-based parallelism.

01:18 And this is where this concurrent.futures module is extremely handy because you know—see? I did it again. I just switched from thread-based execution, or thread-based parallelism, to process-based parallelism.

01:31 This gets around the global interpreter lock problem because every single process has its own interpreter. Therefore, they can all run in parallel, you can actually spread them out across multiple CPU cores, and this solves the global interpreter lock problem.

01:48 But this is definitely something that you need to keep in mind when you’re writing parallel programs in Python. This is also where this concurrent.futures module is kind of nice, because you can change the execution strategy very, very easily.

02:02 And, really, the ProcessPoolExecutor is just a wrapper around the multiprocessing.Pool, but if you’re using this interface, it just becomes so simple to swap out the different execution strategies here.

02:17 Now, we’re back to a ThreadPoolExecutor again, and we’re getting a different result.

Avatar image for alexchwu

alexchwu on July 5, 2019

Awesome lesson and thanks for sharing

Avatar image for konk

konk on July 5, 2019

Good tutorial. I’d read about python multiprocessing/threading, but had not yet implemented it. Seeing it in action in this tutorial - wow - quite easy to get going. No reason not to implement when it will help.

You’ve cleared my doubt about functional programming. Now, the time for question. Can we say that a piece of functional program should only contain function calls with no procedural logic and it should ideally act on immutable data ?

Avatar image for Dan Bader

Dan Bader RP Team on Nov. 30, 2019

Glad you liked the course!

Can we say that a piece of functional program should only contain function calls with no procedural logic and it should ideally act on immutable data?

Great question. Well, my take on this is that I’ll use whatever makes my life and the lives of my colleagues easier :) I’m not a purist when it comes to functional programming.

I find it useful as a technique that I can use when appropriate, but I’m not going to lock myself into writing only pure FP code with 100% immutable data structures.

It might make for a fun exercise to try and attain that, but at the end of the day I’m usually writing code to solve a problem. So I’ll use whatever tools and techniques that make me the most effective in getting to my goal. I don’t feel bad about mixing functional, procedural, and object-oriented programming styles.

Avatar image for Pygator

Pygator on Jan. 20, 2020

I liked taking builtin map from python3 and connecting it with a parallel map idiom from two separate modules to speed up code execution; great place to use FP on a big data structure.

Avatar image for mikesult

mikesult on March 3, 2020

Great tutorial in functional programming. I learned a lot. I’d like to share a newbie mistake I made in the last section. I typed in the code from the video but I named it concurrent.py (bad mistake) and when I tried to run, it caused an error:

ModuleNotFoundError: 
No module named 'concurrent.futures'
'concurrent' is not a package

I fumbled with this for most of the day trying to figure out the problem before I finally found a post from a few years back on stackoverflow that had the same error and one of the answering comments included ‘…Either that or you’re shadowing concurrent. Do you have a concurrent.py?’

Umm, yes I do.

Once I renamed the file it worked as expected.

So I learned that you shouldn’t name your file the same name as a package name. Of course it seems so obvious now.

Thanks for a great intro to the functional programming style.

Avatar image for Axel FAUVEL

Axel FAUVEL on March 27, 2020

Thanks a lot for this course, very well explained :)

Avatar image for Ola Ajibode

Ola Ajibode on March 27, 2020

Got is now! That concurrent.futures bit was very useful particularly when GIL is in the picture. Thanks and kudos!

Avatar image for Dr VINOD KUMAR VERMA

Dr VINOD KUMAR VERMA on March 28, 2020

nice contents.

Avatar image for ibrahim suleiman

ibrahim suleiman on March 29, 2020

is there any project you can suggest to apply the lesson learnt from this course

Avatar image for yashtronp

yashtronp on March 29, 2020

Thanks a lot for this course, very well explained is there any project you can suggest to apply the lesson learnt from this course plz

Avatar image for sroder

sroder on April 1, 2020

That was cool !

Avatar image for Cristian Palau

Cristian Palau on April 6, 2020

Thank you Dan for this great tutorial! :)

Avatar image for zorion

zorion on April 8, 2020

Awesome, thanks Dan! I finally understand what GIL blocks. It was always a black box for me, I knew that there was something wrong in Python parallelism but I didn’t know that it was restricted to threads while computing. Good to know, Good to know!

Avatar image for George Yeboah

George Yeboah on April 10, 2020

Good tutorial I really enjoyed watching it and picking up some cool techniques from it Great work keep it up

Avatar image for darth88vader88

darth88vader88 on April 10, 2020

Thanks for the course, Dan! key takeaway was definitely parallel processing. the discussion was “pure gold” to jump start its use in my coding

Avatar image for radupopa21

radupopa21 on April 10, 2020

Never fully understood the GIL problem and how concurent.futures solves it for us. Thanks you very much for that.

Avatar image for Paul Ricketts

Paul Ricketts on April 11, 2020

I’m super impressed with the clarity of the explanations. And finally I understand what functional programming is, and how handy it can be for multiprocessing. Many thanks!

Avatar image for bennjuguna0

bennjuguna0 on April 13, 2020

Honestly thought it would be harder than this. Many thanks to you for the awesome tutorials.

Avatar image for berry4

berry4 on April 13, 2020

Thank you for this course. I learned a lot from it!

Avatar image for Dave

Dave on April 14, 2020

That was excellent! You do a great job presenting this info.

Your examples were working with a small dataset. How would you populate this type of immutable/named tuples data structure? Would you import to pandas first and then set this up?

Avatar image for pcordero

pcordero on April 15, 2020

Really nice overview and explanation! congrats.

Avatar image for Tomas Menito

Tomas Menito on April 22, 2020

Great tutorial, thanks!

Avatar image for Javier Ruiz

Javier Ruiz on April 22, 2020

This was a very nice present! Thanks Dan and Real Python!

Avatar image for nareshhdfs

nareshhdfs on April 25, 2020

has anyone idea about given error like below while using multiprocessing pool?

**cls(buf, protocol).dump(obj)

TypeError: can’t pickle SSLContext objects

Avatar image for milosvblagojevic

milosvblagojevic on April 25, 2020

Thanks for the course, it is very clear and concise and helpful.

Avatar image for milangnjatovic

milangnjatovic on April 28, 2020

Great course and even greater presentation. Keep it up.

Avatar image for Zarata

Zarata on May 7, 2020

Processes and Threads and GIL, oh my! Processes and Threads and Gil, oh my! … It’s a mind stretcher!! The fact the (implied superior) not-GIL-limited ProcessPoolExec executes in 2 sec while the ThreadPoolExec different result is 1 sec (half) teaches much … but it’s going to be awhile gaining the skill and insight to know precisely what :) ! Wow! Thanks DB. BTW, roughly how much resource hit giving each process its own Py interpreter??

Avatar image for Marcelo Garbarino

Marcelo Garbarino on May 31, 2020

Excellent course! Thank you!

Avatar image for sufuang

sufuang on June 7, 2020

Nice & great presentation. It helps to understand multiprocessing, concurrent feature, and GIL block better. Is any way to get the codes and supporting material for this course? Thanks!

Avatar image for sroux53

sroux53 on June 23, 2020

Excellent !

Avatar image for SUDHANSHU TIWARI

SUDHANSHU TIWARI on June 28, 2020

nicely teached even an intermidiate like me can also understand 👍👍

Avatar image for SEOTrafficHack DigitalSEO Marketing auto

SEOTrafficHack DigitalSEO Marketing auto on July 19, 2020

Great practical applications possibilites for one of most efficient derived data types - namedtuples. For SEO tasks I did namedtuples classes to automate mapping of scrapped data keywords with their attributes. This course is great supplement how to process, map, join, combine and save time running processing data with multiple attributes.

Avatar image for Divyanshu Sharma

Divyanshu Sharma on July 27, 2020

Can you explain how does multiprocessing.dummy compare to concurrent.futures.ThreadPoolExecutor ?

Avatar image for Bartosz Zaczyński

Bartosz Zaczyński RP Team on Aug. 3, 2020

The concurrent.futures package came with Python 3.2, which was years after the multiprocessing.dummy. It was modeled after the Execution Framework from Java 5 and is now the preferred API for implementing thread pools in Python. That said, you still might want to use multiprocessing.dummy as an adapter layer for legacy code.

Avatar image for Ghani

Ghani on Oct. 14, 2020

This functional programming course is really excellent! Although I need to revise it and chew it again, I learned plenty of ways I can make my code more efficient. Thanks Dan.

Avatar image for paulagm12

paulagm12 on Nov. 15, 2020

Great course! It is explained in a very clear way and I have learnt a lot of new and useful things to put into practise in my programming. I really appreciate all the effort put into this.

Avatar image for squeakyboots

squeakyboots on April 27, 2021

Thanks so much for this course! I’m excited to try applying this to my own API calls when something might be running more slowly than I’d like.

Avatar image for MOSTA

MOSTA on June 4, 2021

Great contents and clear presentation. Now I have to do my own practicing.

Avatar image for samuelebright

samuelebright on Jan. 30, 2022

Thank you Dan for this course. I’m looking forward to storing data from Excel sheets in immutable data structures and then using some of the strategies from the videos to manipulate the data for use in my programs.

Avatar image for MarkYoung

MarkYoung on Sept. 25, 2023

Great course. Number 1 takeway for me was an answer as to why to keep functions (that will be parallelized) small and with no side-effects. An open question I had is that if I don’t use map() to apply a function to an iterator, can that still be parallelized?

Avatar image for mihail-t

mihail-t on Dec. 1, 2024

You recommend using process-based parallelism, but I have seen advice in multiple other places, where they recommend process-based for CPU-heavy tasks and thread-based for IO-heavy tasks. Also, in the Python docs it says ‘the GIL is always released when doing I/O.’ What about that?

Avatar image for Bartosz Zaczyński

Bartosz Zaczyński RP Team on Dec. 2, 2024

(…) but I have seen advice in multiple other places, where they recommend process-based for CPU-heavy tasks and thread-based for IO-heavy tasks.

@mihail-t That’s perfectly reasonable advice, which doesn’t contradict what Dan is already explaining in the video lesson.

In a nutshell, the GIL prevents multiple threads from running at the same time in Python, which means that only one thread can execute at a time. This renders Python threads useless for CPU-bound tasks that you wish to run in parallel. On the other hand, threads can still be beneficial for I/O-bound tasks, which mostly wait for data to arrive, e.g., through the network. Historically, the only way to run multiple tasks in parallel with Python has been to run them in separate interpreter processes.

If you want to learn more about these topics, including the GIL, then you’ll find plenty of Real Python resources that explore them:

Note: The concurrent.futures package provides a high-level interface on top of both threading and multiprocessing, which was modeled after Java’s executor framework API.

Become a Member to join the conversation.