Since this question was asked in 2010, there has been real simplification in how to do simple multithreading with Python with map and pool.

The code below comes from an article/blog post that you should definitely check out (no affiliation) - Parallelism in one line: A Better Model for Day to Day Threading Tasks. I'll summarize below - it ends up being just a few lines of code:

from multiprocessing.dummy import Pool as ThreadPool
pool = ThreadPool(4)
results = pool.map(my_function, my_array)

Which is the multithreaded version of:

results = []
for item in my_array:
    results.append(my_function(item))

Description

Map is a cool little function, and the key to easily injecting parallelism into your Python code. For those unfamiliar, map is something lifted from functional languages like Lisp. It is a function which maps another function over a sequence.

Map handles the iteration over the sequence for us, applies the function, and stores all of the results in a handy list at the end.


Implementation

Parallel versions of the map function are provided by two libraries:multiprocessing, and also its little known, but equally fantastic step child:multiprocessing.dummy.

multiprocessing.dummy is exactly the same as multiprocessing module, but uses threads instead (an important distinction - use multiple processes for CPU-intensive tasks; threads for (and during) I/O):

multiprocessing.dummy replicates the API of multiprocessing, but is no more than a wrapper around the threading module.

import urllib2
from multiprocessing.dummy import Pool as ThreadPool

urls = [
  'http://www.python.org',
  'http://www.python.org/about/',
  'http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html',
  'http://www.python.org/doc/',
  'http://www.python.org/download/',
  'http://www.python.org/getit/',
  'http://www.python.org/community/',
  'https://wiki.python.org/moin/',
]

# Make the Pool of workers
pool = ThreadPool(4)

# Open the URLs in their own threads
# and return the results
results = pool.map(urllib2.urlopen, urls)

# Close the pool and wait for the work to finish
pool.close()
pool.join()

And the timing results:

Single thread:   14.4 seconds
       4 Pool:   3.1 seconds
       8 Pool:   1.4 seconds
      13 Pool:   1.3 seconds

Passing multiple arguments (works like this only in Python 3.3 and later):

To pass multiple arrays:

results = pool.starmap(function, zip(list_a, list_b))

Or to pass a constant and an array:

results = pool.starmap(function, zip(itertools.repeat(constant), list_a))

If you are using an earlier version of Python, you can pass multiple arguments via this workaround).

(Thanks to user136036 for the helpful comment.)

Answer from philshem on Stack Overflow
🌐
Python
docs.python.org › 3 › library › threading.html
threading — Thread-based parallelism — Python 3.14.4 documentation
As of Python 3.13, free-threaded builds can disable the GIL, enabling true parallel execution of threads, but this feature is not available by default (see PEP 703).
🌐
Real Python
realpython.com › intro-to-python-threading
An Intro to Threading in Python – Real Python
August 5, 2024 - The Python standard library provides threading, which contains most of the primitives you’ll see in this article. Thread, in this module, nicely encapsulates threads, providing a clean interface to work with them. To start a separate thread, you create a Thread instance and then tell it to .start(): ... 1import logging 2import threading 3import time 4 5def thread_function(name): 6 logging.info("Thread %s: starting", name) 7 time.sleep(2) 8 logging.info("Thread %s: finishing", name) 9 10if __name__ == "__main__": 11 format = "%(asctime)s: %(message)s" 12 logging.basicConfig(format=format, lev
Discussions

multithreading - How do I use threading in Python? - Stack Overflow
It seems like it attempts to multiprocess != multithread 2015-07-29T11:02:00.173Z+00:00 ... By the way, guys, you can write with Pool(8) as p: p.map( *whatever* ) and get rid of bookkeeping lines too. 2015-09-03T07:06:44.937Z+00:00 ... @BarafuAlbino: Useful as that is, it's probably worth noting that this only works in Python 3... More on stackoverflow.com
🌐 stackoverflow.com
Does Python support multithreading? Can it speed up execution time? - Stack Overflow
I'm slightly confused about whether multithreading works in Python or not. I know there has been a lot of questions about this and I've read many of them, but I'm still confused. I know from my own More on stackoverflow.com
🌐 stackoverflow.com
Why multithreading isn't real in Python (explain it to a 5 year old)
Imagine an intersection being conducted by a traffic cop. Even though there are cars sitting and running on both streets, only one can actually move at a time. When the cars on one street go, the others are still sitting there, waiting, with no update to their position. Until the conductor waves them on. Now imagine an n-dimensional cross street. Because the conductor wants to be safe, he can still only let cars go from one incoming street at a time, although he has discretion over which street and how many cars should go. No matter how many streets are added to the n dimensional intersection, the conductor can only let one go at a time. More on reddit.com
🌐 r/learnpython
101
279
March 6, 2020
Real Multithreading is Coming to Python - Learn How You Can Use It Now
Shi, I’m about getting deprecated. The GIL defines so many implications, that I’m afraid that my entire worldview will fall apart. More on reddit.com
🌐 r/Python
112
618
May 14, 2023
People also ask

How are Python multithreading and multiprocessing related?

Both multithreading and multiprocessing allow Python code to run concurrently. Only multiprocessing will allow your code to be truly parallel. However, if your code is IO-heavy (like HTTP requests), then multithreading will still probably speed up your code.

🌐
toptal.com
toptal.com › python › beginners-guide-to-concurrency-and-parallelism-in-python
Python Multithreading Tutorial: Concurrency and Parallelism | Toptal®
What is multithreading?

Multithreading (sometimes simply “threading”) is when a program creates multiple threads with execution cycling among them, so one longer-running task doesn’t block all the others. This works well for tasks that can be broken down into smaller subtasks, which can then each be given to a thread to be completed.

🌐
toptal.com
toptal.com › python › beginners-guide-to-concurrency-and-parallelism-in-python
Python Multithreading Tutorial: Concurrency and Parallelism | Toptal®
What's the difference between Python threading and multiprocessing?

With threading, concurrency is achieved using multiple threads, but due to the GIL only one thread can be running at a time. In multiprocessing, the original process is forked process into multiple child processes bypassing the GIL. Each child process will have a copy of the entire program’s memory.

🌐
toptal.com
toptal.com › python › beginners-guide-to-concurrency-and-parallelism-in-python
Python Multithreading Tutorial: Concurrency and Parallelism | Toptal®
🌐
GeeksforGeeks
geeksforgeeks.org › python › multithreading-python-set-1
Multithreading in Python - GeeksforGeeks
October 3, 2025 - A multithreaded process can run multiple tasks in parallel by having separate stacks/registers for each thread, but sharing the same code and data. Python provides the threading module to work with threads.
🌐
Toptal
toptal.com › python › beginners-guide-to-concurrency-and-parallelism-in-python
Python Multithreading Tutorial: Concurrency and Parallelism | Toptal®
May 16, 2018 - RQ is easy to use and covers simple use cases extremely well, but if more advanced options are required, other Python 3 queue solutions (such as Celery) can be used. If your code is IO bound, both multiprocessing and multithreading in Python will work for you.
Top answer
1 of 16
1660

Since this question was asked in 2010, there has been real simplification in how to do simple multithreading with Python with map and pool.

The code below comes from an article/blog post that you should definitely check out (no affiliation) - Parallelism in one line: A Better Model for Day to Day Threading Tasks. I'll summarize below - it ends up being just a few lines of code:

from multiprocessing.dummy import Pool as ThreadPool
pool = ThreadPool(4)
results = pool.map(my_function, my_array)

Which is the multithreaded version of:

results = []
for item in my_array:
    results.append(my_function(item))

Description

Map is a cool little function, and the key to easily injecting parallelism into your Python code. For those unfamiliar, map is something lifted from functional languages like Lisp. It is a function which maps another function over a sequence.

Map handles the iteration over the sequence for us, applies the function, and stores all of the results in a handy list at the end.


Implementation

Parallel versions of the map function are provided by two libraries:multiprocessing, and also its little known, but equally fantastic step child:multiprocessing.dummy.

multiprocessing.dummy is exactly the same as multiprocessing module, but uses threads instead (an important distinction - use multiple processes for CPU-intensive tasks; threads for (and during) I/O):

multiprocessing.dummy replicates the API of multiprocessing, but is no more than a wrapper around the threading module.

import urllib2
from multiprocessing.dummy import Pool as ThreadPool

urls = [
  'http://www.python.org',
  'http://www.python.org/about/',
  'http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html',
  'http://www.python.org/doc/',
  'http://www.python.org/download/',
  'http://www.python.org/getit/',
  'http://www.python.org/community/',
  'https://wiki.python.org/moin/',
]

# Make the Pool of workers
pool = ThreadPool(4)

# Open the URLs in their own threads
# and return the results
results = pool.map(urllib2.urlopen, urls)

# Close the pool and wait for the work to finish
pool.close()
pool.join()

And the timing results:

Single thread:   14.4 seconds
       4 Pool:   3.1 seconds
       8 Pool:   1.4 seconds
      13 Pool:   1.3 seconds

Passing multiple arguments (works like this only in Python 3.3 and later):

To pass multiple arrays:

results = pool.starmap(function, zip(list_a, list_b))

Or to pass a constant and an array:

results = pool.starmap(function, zip(itertools.repeat(constant), list_a))

If you are using an earlier version of Python, you can pass multiple arguments via this workaround).

(Thanks to user136036 for the helpful comment.)

2 of 16
769

Here's a simple example: you need to try a few alternative URLs and return the contents of the first one to respond.

import Queue
import threading
import urllib2

# Called by each thread
def get_url(q, url):
    q.put(urllib2.urlopen(url).read())

theurls = ["http://google.com", "http://yahoo.com"]

q = Queue.Queue()

for u in theurls:
    t = threading.Thread(target=get_url, args = (q,u))
    t.daemon = True
    t.start()

s = q.get()
print s

This is a case where threading is used as a simple optimization: each subthread is waiting for a URL to resolve and respond, to put its contents on the queue; each thread is a daemon (won't keep the process up if the main thread ends -- that's more common than not); the main thread starts all subthreads, does a get on the queue to wait until one of them has done a put, then emits the results and terminates (which takes down any subthreads that might still be running, since they're daemon threads).

Proper use of threads in Python is invariably connected to I/O operations (since CPython doesn't use multiple cores to run CPU-bound tasks anyway, the only reason for threading is not blocking the process while there's a wait for some I/O). Queues are almost invariably the best way to farm out work to threads and/or collect the work's results, by the way, and they're intrinsically threadsafe, so they save you from worrying about locks, conditions, events, semaphores, and other inter-thread coordination/communication concepts.

🌐
Dataquest
dataquest.io › blog › multithreading-in-python
Multithreading in Python: The Ultimate Guide (with Coding Examples)
November 8, 2024 - In this tutorial, we'll show you how to achieve parallelism in your code by using multithreading techniques in Python.
Find elsewhere
🌐
Tutorialspoint
tutorialspoint.com › python › python_multithreading.htm
Python - Multithreading
To create and start a new thread in Python, you can use either the low-level _thread module or the higher-level threading module. The threading module is generally recommended due to its additional features and ease of use.
🌐
Python documentation
docs.python.org › 3 › howto › free-threading-python.html
Python support for free threading — Python 3.14.4 documentation
Starting with the 3.13 release, CPython has support for a build of Python called free threading where the global interpreter lock (GIL) is disabled. Free-threaded execution allows for full utilization of the available processing power by running threads in parallel on available CPU cores.
🌐
Python
docs.python.org › 3 › library › multiprocessing.html
multiprocessing — Process-based parallelism — Python 3.14.4 documentation
February 23, 2026 - The child process, when it begins, is effectively identical to the parent process. All resources of the parent are inherited by the child process. Note that safely forking a multithreaded process is problematic. Available on POSIX systems. Changed in version 3.14: This is no longer the default ...
🌐
Mimo
mimo.org › glossary › python › multithreading
Python Multithreading: Syntax, Usage, and Examples
Python multithreading allows you to run multiple threads in parallel within a single process. This is especially useful for I/O-bound tasks like handling multiple web requests, reading files, or making API calls. Python’s threading module makes it easy to create and manage threads for concurrent ...
Top answer
1 of 6
196

The GIL does not prevent threading. All the GIL does is make sure only one thread is executing Python code at a time; control still switches between threads.

What the GIL prevents then, is making use of more than one CPU core or separate CPUs to run threads in parallel.

This only applies to Python code. C extensions can and do release the GIL to allow multiple threads of C code and one Python thread to run across multiple cores. This extends to I/O controlled by the kernel, such as select() calls for socket reads and writes, making Python handle network events reasonably efficiently in a multi-threaded multi-core setup.

What many server deployments then do, is run more than one Python process, to let the OS handle the scheduling between processes to utilize your CPU cores to the max. You can also use the multiprocessing library to handle parallel processing across multiple processes from one codebase and parent process, if that suits your use cases.

Note that the GIL is only applicable to the CPython implementation; Jython and IronPython use a different threading implementation (the native Java VM and .NET common runtime threads respectively).

To address your update directly: Any task that tries to get a speed boost from parallel execution, using pure Python code, will not see a speed-up as threaded Python code is locked to one thread executing at a time. If you mix in C extensions and I/O, however (such as PIL or numpy operations) and any C code can run in parallel with one active Python thread.

Python threading is great for creating a responsive GUI, or for handling multiple short web requests where I/O is the bottleneck more than the Python code. It is not suitable for parallelizing computationally intensive Python code, stick to the multiprocessing module for such tasks or delegate to a dedicated external library.

2 of 6
8

Yes. :)

You have the low level thread module and the higher level threading module. But if you simply want to use multicore machines, the multiprocessing module is the way to go.

Quote from the docs:

In CPython, due to the Global Interpreter Lock, only one thread can execute Python code at once (even though certain performance-oriented libraries might overcome this limitation). If you want your application to make better use of the computational resources of multi-core machines, you are advised to use multiprocessing. However, threading is still an appropriate model if you want to run multiple I/O-bound tasks simultaneously.

🌐
Intel
intel.com › content › www › us › en › developer › articles › technical › easy-guide-to-multithreading-in-python.html
Needle and Thread – An Easy Guide to Multithreading in Python
NumPy and SciPy are Python libraries specifically designed for numerical processing and scientific computing, respectively. One workaround to enable multithreading/parallelism in Python programs is to expose parallelism on all the possible levels of a program, such as by parallelizing the outermost loops or by using other functional or pipeline types of parallelism on the application level.
🌐
Turing
turing.com › kb › python-multiprocessing-vs-multithreading
Python Multiprocessing vs Multithreading.
But in the case of Python 3, the threads appear to be executing simultaneously. In software development, a thread simply means a task that often paves the way for Python developers to streamline the concurrency of the programs.
🌐
Pieces
pieces.app › home
Python Multithreading: Benefits, Use Cases, and Comparison
Pieces for Developers – Long-Term Memory Agent
For instance, if you are running three processes on your Python program and, for some reason, process 2 is slow, processes 1 and 3 would still be executed irrespective of process 2 speed. Multiprocessing differs from multithreading, where each thread depends on the other during execution. Pieces is your AI long-term memory agent that captures live context from browsers to IDEs and tools, manages snippets, and supports multiple LLMs. This app has dramatically improved my workflow!
Rating: 5 ​
🌐
Troy Fawkes
troyfawkes.com › home › blog › the basics of python multithreading and queues
The Basics of Python Multithreading and Queues - Troy Fawkes
May 13, 2024 - Multithreading in Python, for example. Or how to use Queues. So here’s something for myself next time I need a refresher. It’s the bare-bones concepts of Queuing and Threading in Python. Before you do anything else, import Queue. ... my_list = [] my_list.append(1) my_list.append(2) my_list.append(3) print my_list.pop(0) # Outputs: 1
🌐
Reddit
reddit.com › r/learnpython › why multithreading isn't real in python (explain it to a 5 year old)
r/learnpython on Reddit: Why multithreading isn't real in Python (explain it to a 5 year old)
March 6, 2020 -

I'm really confused at all the explanations at why python can't achieve "real" multithreading due to the GIL.

Could someone explain it to someone who isn't well versed in concurrency? Thanks!

🌐
Reddit
reddit.com › r/python › real multithreading is coming to python - learn how you can use it now
r/Python on Reddit: Real Multithreading is Coming to Python - Learn How You Can Use It Now
May 14, 2023 - I understand GIL limits code exec to one thread but how does "usual" threading is like without GIL. ... Free-threaded (multicore, parallel) Python will be fully supported starting Python 3...
🌐
Scaler
scaler.com › topics › multithreading-in-python
Multithreading in Python | What is Multithreading? - Scaler Topics
May 31, 2022 - In simple words, the ability of a processor to execute multiple threads simultaneously is known as multithreading. Python multithreading facilitates sharing data space and resources of multiple threads with the main thread.
🌐
Medium
medium.com › @pankaj_pandey › boosting-your-python-application-performance-the-power-of-multithreading-695383244f60
Boosting Your Python Application Performance: The Power of Multithreading | by Pankaj | Medium
March 19, 2023 - Multithreading is a programming technique that allows multiple threads to run concurrently within a single program. A thread is a lightweight process that can be scheduled independently by the operating system.