Understanding Python Threads, Processes, GIL, and Multiprocessing
This article explains the fundamental differences between threads and processes, the role of Python's Global Interpreter Lock (GIL), and how to use the multiprocessing package—including Process, Pool, Queue, Pipe, and synchronization primitives—as well as an overview of concurrent.futures for high‑level concurrent programming in Python.
Thread and Process Differences
In operating systems, a process is the smallest unit of resource allocation, while a thread is the smallest unit of CPU scheduling; threads share a process's address space and resources, making context switches cheaper and improving concurrency.
Key distinctions include address‑space isolation, communication methods (IPC for processes, shared memory for threads), scheduling overhead, and reliability (a crash in one thread can bring down the whole process).
Python Global Interpreter Lock (GIL)
The GIL ensures that only one thread executes Python bytecode at a time in CPython, simplifying the interpreter but limiting true parallelism on multi‑core CPUs. It benefits single‑threaded performance and C‑extension integration, but causes thread thrashing on CPU‑bound workloads.
Since Python 3.2 the GIL is released after a fixed timeout (≈5 ms) when other threads request it, improving fairness on multi‑core systems.
Mitigating GIL Impact
Upgrade to newer Python versions with optimized GIL handling.
Use multiprocessing instead of multithreading for CPU‑bound tasks.
Pin threads to specific CPUs (affinity).
Employ GIL‑free interpreters such as Jython or IronPython.
Prefer I/O‑bound workloads for threading.
Use coroutines (asyncio) for efficient single‑threaded concurrency.
Write performance‑critical sections in C/C++ extensions (with nogil).
Python Multiprocessing Package
The multiprocessing module provides a process‑based parallelism API that mirrors the threading interface, allowing easy migration from threads to processes. Each process has its own GIL, eliminating GIL contention.
Process
Creates a new process.
from multiprocessing import Process
import os
def run(name):
print('Run child process %s (%s)...' % (name, os.getpid()))
if __name__ == '__main__':
print('Parent process %s.' % os.getpid())
p = Process(target=run, args=('test',))
p.start()
p.join()
print('Child process end.')Pool
Manages a pool of worker processes, reusing them for multiple tasks.
from multiprocessing import Pool
def test(i):
print(i)
if __name__ == '__main__':
pool = Pool(8)
pool.map(test, range(100))
pool.close()
pool.join()Queue, JoinableQueue
Provides inter‑process communication via FIFO queues.
from multiprocessing import Process, Queue
import os, time, random
def write(q):
for v in ['A','B','C']:
q.put(v)
time.sleep(random.random())
def read(q):
while True:
v = q.get(True)
print('Got', v)
if __name__ == '__main__':
q = Queue()
pw = Process(target=write, args=(q,))
pr = Process(target=read, args=(q,))
pw.start(); pr.start()
pw.join(); pr.terminate()Value and Array
Shared memory objects for simple data types.
from multiprocessing import Value, Array, Process
def f(num, arr):
num.value = 3.14
arr[0] = 5
if __name__ == '__main__':
num = Value('d', 0.0)
arr = Array('i', range(10))
p = Process(target=f, args=(num, arr))
p.start(); p.join()
print(num.value, arr[:])Pipe
Creates a two‑way communication channel.
from multiprocessing import Process, Pipe
import time
def child(conn):
time.sleep(1)
conn.send('Hello')
print('Child received', conn.recv())
conn.close()
if __name__ == '__main__':
parent, child_conn = Pipe()
p = Process(target=child, args=(child_conn,))
p.start()
print('Parent received', parent.recv())
parent.send('OK')
p.join()Manager
Runs a server process that hosts shared objects (list, dict, Namespace, etc.) accessible via proxies.
import multiprocessing as mp
def f(x, arr, lst, dct, ns):
x.value = 3.14
arr[0] = 5
lst.append('Hello')
dct[1] = 2
ns.a = 10
if __name__ == '__main__':
mgr = mp.Manager()
x = mgr.Value('d', 0.0)
arr = mgr.Array('i', range(10))
lst = mgr.list()
dct = mgr.dict()
ns = mgr.Namespace()
p = mp.Process(target=f, args=(x, arr, lst, dct, ns))
p.start(); p.join()
print(x.value, arr[:], lst, dct, ns)Synchronization Primitives
Lock : Simple mutex.
RLock : Re‑entrant lock.
Semaphore : Allows a limited number of concurrent accesses.
Condition : Advanced lock with wait/notify semantics.
Event : Simple flag for signaling between processes.
Example: Using Lock
from multiprocessing import Process, Lock
def worker(l, n):
l.acquire()
print('Hello Num:', n)
l.release()
if __name__ == '__main__':
lock = Lock()
for i in range(20):
Process(target=worker, args=(lock, i)).start()concurrent.futures
High‑level API introduced in Python 3.2 that provides ThreadPoolExecutor and ProcessPoolExecutor for easy asynchronous execution.
Submitting Tasks
from concurrent.futures import ThreadPoolExecutor
import time
def test(num):
return time.ctime(), num
with ThreadPoolExecutor(max_workers=1) as exe:
fut = exe.submit(test, 1)
print(fut.result())Mapping Over Iterables
from concurrent.futures import ThreadPoolExecutor
def test(num):
return time.ctime(), num
with ThreadPoolExecutor(max_workers=1) as exe:
for result in exe.map(test, [1,2,3]):
print(result)Future API
Futures expose methods such as result(), exception(), cancel(), and utilities like as_completed() and wait() for coordinating multiple asynchronous operations.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Python Programming Learning Circle
A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
