Fundamentals 17 min read

Why Python Threads Can’t Fully Utilize Multi‑Core CPUs and How to Use Them Effectively

This tutorial explains Python's multithreading model, its advantages and limitations—including the Global Interpreter Lock—demonstrates thread creation with the threading module, shows race conditions and lock usage, compares processes and threads, and discusses when to choose threads, processes, or asynchronous I/O for different workloads.

Python Crawling & Data Mining
Python Crawling & Data Mining
Python Crawling & Data Mining
Why Python Threads Can’t Fully Utilize Multi‑Core CPUs and How to Use Them Effectively

Multithreading in Python

Python supports true OS‑level threads (Posix threads) via its threading module, but due to the Global Interpreter Lock (GIL) only one thread executes Python bytecode at a time.

Advantages of multithreading

Long‑running tasks can be moved to background threads.

User interfaces stay responsive; progress can be shown.

Potential speed‑up when tasks spend time waiting (I/O, user input, etc.).

Resources such as memory can be shared among threads.

Thread types

Kernel threads : created and destroyed by the operating system.

User threads : implemented in user space without kernel support.

Python threading modules

The low‑level _thread module provides basic primitives, while the high‑level threading module wraps it and is recommended for most use cases.

Example: Download files with threads

from random import randint
from threading import Thread, current_thread
from time import time, sleep

def download(filename):
    print('thread %s is running...' % current_thread().name)
    print('开始下载%s...' % filename)
    time_to_download = randint(5, 10)
    sleep(time_to_download)
    print('%s下载完成! 耗费了%d秒' % (filename, time_to_download))

def download_multi_threading():
    print('thread %s is running...' % current_thread().name)
    start = time()
    t1 = Thread(target=download, args=('Python.pdf',), name='subthread-1')
    t1.start()
    t2 = Thread(target=download, args=('nazha.mkv',), name='subthread-2')
    t2.start()
    t1.join()
    t2.join()
    end = time()
    print('总共耗费了%.3f秒' % (end - start))
    print('thread %s is running...' % current_thread().name)

if __name__ == '__main__':
    download_multi_threading()

Threads are created with Thread, specifying the target function, arguments, and an optional name. The main thread can start, join, and monitor child threads.

Lock and race conditions

When multiple threads modify a shared variable, race conditions can corrupt data because each operation consists of several steps that may be interleaved.

from threading import Thread
from time import sleep

balance = 0

def change_it(n):
    global balance
    balance = balance + n
    balance = balance - n

def run_thread(n):
    for i in range(100000):
        change_it(n)

def nolock_multi_thread():
    t1 = Thread(target=run_thread, args=(5,))
    t2 = Thread(target=run_thread, args=(8,))
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print(balance)

if __name__ == '__main__':
    nolock_multi_thread()

Running the code often prints a non‑zero balance (e.g., -8) because the two threads interleave the read‑modify‑write steps.

Using a lock to protect shared data

from threading import Thread, Lock
from time import sleep

balance = 0
lock = Lock()

def change_it(n):
    global balance
    balance = balance + n
    balance = balance - n

def run_thread_lock(n):
    for i in range(100000):
        lock.acquire()
        try:
            change_it(n)
        finally:
            lock.release()

def lock_multi_thread():
    t1 = Thread(target=run_thread_lock, args=(5,))
    t2 = Thread(target=run_thread_lock, args=(8,))
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print(balance)

if __name__ == '__main__':
    lock_multi_thread()

The lock ensures that only one thread modifies balance at a time, guaranteeing the final result is zero.

GIL limitation

CPython’s Global Interpreter Lock forces a thread to acquire the GIL before executing bytecode and releases it after about 100 bytecode instructions, so CPU‑bound Python threads cannot run truly in parallel; they merely interleave on a single core.

Process vs Thread

Processes provide higher stability because each has its own memory space; a crash in one does not affect others. Threads share memory, offering faster context switches but lower fault isolation. Creating processes is heavier, especially on Windows, while threads are lighter.

Master‑Worker model

Typical concurrent designs use a master (or manager) to distribute tasks to multiple workers, which can be implemented with either processes or threads.

Compute‑bound vs I/O‑bound tasks

Compute‑intensive workloads (e.g., video encoding) benefit from multiple processes to bypass the GIL. I/O‑intensive workloads (network, disk) can achieve good performance with multithreading because threads spend most of their time waiting.

Asynchronous I/O and coroutines

Modern OSes support asynchronous I/O, allowing a single‑threaded event‑driven model (coroutines) to handle many I/O tasks efficiently. In Python, async/await provides this model, eliminating the need for thread‑level locks.

References

https://www.liaoxuefeng.com/wiki/1016959663602400/1017627212385376

https://github.com/jackfrued/Python-100-Days/blob/master/Day01-15/13.%E8%BF%9B%E7%A8%8B%E5%92%8C%E7%BA%BF%E7%A8%8B.md

https://www.runoob.com/python3/python3-multithreading.html

The full source code is available at GitHub .

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

PythonmultithreadingThreadLocalLockGIL
Python Crawling & Data Mining
Written by

Python Crawling & Data Mining

Life's short, I code in Python. This channel shares Python web crawling, data mining, analysis, processing, visualization, automated testing, DevOps, big data, AI, cloud computing, machine learning tools, resources, news, technical articles, tutorial videos and learning materials. Join us!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.