3848 字
19 分钟

Python 并发编程完全指南:threading / multiprocessing / concurrent.futures 深度解析与实战

Python 并发编程是提升程序性能的关键技能。由于 GIL 的存在,Python 的并发编程与其他语言有显著差异。理解 threading、multiprocessing 和 concurrent.futures 的适用场景,是写出高效 Python 并发程序的基础。

Python 并发编程示意图

本文全面讲解 Python 并发编程:

  • GIL 原理与影响
  • threading 多线程编程
  • multiprocessing 多进程编程
  • concurrent.futures 线程池与进程池
  • 同步原语(Lock / RLock / Semaphore / Event / Condition)
  • Queue 线程安全队列
  • 进程间通信(Pipe / Queue / SharedMemory)
  • CPU 密集型 vs IO 密集型策略选择
  • 实战场景与最佳实践

一、GIL 原理与影响#

1.1 什么是 GIL#

# GIL(Global Interpreter Lock)是 CPython 中的一个互斥锁
# 确保同一时刻只有一个线程执行 Python 字节码
# 验证 GIL 的存在
import threading
import time
def count_down(n):
while n > 0:
n -= 1
# 单线程
start = time.time()
count_down(100_000_000)
single_time = time.time() - start
print(f"单线程: {single_time:.2f}s")
# 多线程(受 GIL 限制,不会加速)
t1 = threading.Thread(target=count_down, args=(50_000_000,))
t2 = threading.Thread(target=count_down, args=(50_000_000,))
start = time.time()
t1.start()
t2.start()
t1.join()
t2.join()
multi_time = time.time() - start
print(f"多线程: {multi_time:.2f}s")
# 结果:多线程可能更慢(线程切换开销)
# 单线程: 3.21s
# 多线程: 3.45s

1.2 GIL 的影响范围#

# GIL 在以下场景中不影响性能:
# 1. IO 操作(自动释放 GIL)
import urllib.request
def fetch_url(url):
response = urllib.request.urlopen(url)
return response.read()
# 2. time.sleep(释放 GIL)
import time
time.sleep(1) # 其他线程可以执行
# 3. C 扩展(可手动释放 GIL)
import numpy as np
# NumPy 底层在计算时释放 GIL
# GIL 在以下场景中严重影响性能:
# 1. CPU 密集型 Python 代码
# 2. 纯 Python 循环计算
# 3. 大量 Python 对象操作

1.3 应对策略#

# 策略选择决策树
"""
任务类型?
├── IO 密集型(网络/文件/数据库)
│ ├── 低并发 → threading
│ ├── 高并发 → asyncio
│ └── 简单并行 → ThreadPoolExecutor
├── CPU 密集型(计算/加密/图像处理)
│ ├── 简单并行 → ProcessPoolExecutor
│ ├── 需要精细控制 → multiprocessing
│ └── 大规模数据 → multiprocessing + SharedMemory
└── 混合型
└── ThreadPoolExecutor + ProcessPoolExecutor 组合
"""

二、threading 多线程编程#

2.1 创建线程#

import threading
import time
# 方法1:函数方式
def worker(name, delay):
print(f"线程 {name} 开始")
time.sleep(delay)
print(f"线程 {name} 完成")
t1 = threading.Thread(target=worker, args=("A", 2))
t2 = threading.Thread(target=worker, args=("B", 3))
t1.start() # 启动线程
t2.start()
t1.join() # 等待线程完成
t2.join()
print("所有线程完成")
# 方法2:继承 Thread 类
class MyThread(threading.Thread):
def __init__(self, name, delay):
super().__init__()
self.name = name
self.delay = delay
def run(self):
print(f"线程 {self.name} 开始")
time.sleep(self.delay)
print(f"线程 {self.name} 完成")
t = MyThread("C", 2)
t.start()
t.join()

2.2 线程状态与生命周期#

import threading
def task():
import time
time.sleep(2)
t = threading.Thread(target=task)
# 线程状态
print(t.is_alive()) # False(未启动)
print(t.daemon) # False(非守护线程)
t.start()
print(t.is_alive()) # True(运行中)
print(t.name) # Thread-1
print(t.ident) # 线程ID
t.join() # 等待完成
print(t.is_alive()) # False
# 守护线程(主线程退出时自动结束)
daemon_t = threading.Thread(target=task, daemon=True)
# 或
daemon_t = threading.Thread(target=task)
daemon_t.daemon = True
daemon_t.start()
# 主线程退出时,daemon_t 会被强制终止

2.3 获取线程返回值#

import threading
# 方法1:共享变量
def worker(result, key):
result[key] = "computed value"
result = {}
t = threading.Thread(target=worker, args=(result, "data"))
t.start()
t.join()
print(result["data"]) # "computed value"
# 方法2:继承 Thread,重写 run
class ResultThread(threading.Thread):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.result = None
def run(self):
if self._target:
self.result = self._target(*self._args, **self._kwargs)
def compute(x, y):
return x + y
t = ResultThread(target=compute, args=(10, 20))
t.start()
t.join()
print(t.result) # 30

三、同步原语#

3.1 Lock(互斥锁)#

import threading
# 问题:线程不安全
counter = 0
def unsafe_increment():
global counter
for _ in range(1_000_000):
counter += 1 # 非原子操作
t1 = threading.Thread(target=unsafe_increment)
t2 = threading.Thread(target=unsafe_increment)
t1.start()
t2.start()
t1.join()
t2.join()
print(f"预期: 2000000, 实际: {counter}") # 实际 < 2000000
# 解决:使用 Lock
counter = 0
lock = threading.Lock()
def safe_increment():
global counter
for _ in range(1_000_000):
with lock: # 自动获取和释放锁
counter += 1
t1 = threading.Thread(target=safe_increment)
t2 = threading.Thread(target=safe_increment)
t1.start()
t2.start()
t1.join()
t2.join()
print(f"预期: 2000000, 实际: {counter}") # 2000000 ✅

3.2 RLock(可重入锁)#

import threading
# Lock 的问题:同一线程不能多次获取
lock = threading.Lock()
lock.acquire()
# lock.acquire() # 死锁!
# RLock 解决:同一线程可多次获取
rlock = threading.RLock()
rlock.acquire()
rlock.acquire() # ✅ 同一线程可以多次获取
rlock.release()
rlock.release()
# 实际应用:递归调用
class BankAccount:
def __init__(self, balance=0):
self.balance = balance
self.lock = threading.RLock()
def deposit(self, amount):
with self.lock:
self.balance += amount
def withdraw(self, amount):
with self.lock:
if self.balance >= amount:
self.balance -= amount
return True
return False
def transfer(self, other, amount):
with self.lock: # 外层加锁
if self.withdraw(amount): # 内层也需要锁 → RLock
other.deposit(amount)
return True
return False

3.3 Semaphore(信号量)#

import threading
import time
import random
# 限制同时访问的线程数(如数据库连接池)
semaphore = threading.Semaphore(3) # 最多 3 个线程同时执行
def worker(worker_id):
print(f"Worker {worker_id} 等待获取信号量")
with semaphore:
print(f"Worker {worker_id} 开始工作")
time.sleep(random.uniform(0.5, 2.0))
print(f"Worker {worker_id} 完成")
threads = [threading.Thread(target=worker, args=(i,)) for i in range(10)]
for t in threads:
t.start()
for t in threads:
t.join()
# 同时只有 3 个 Worker 在工作

3.4 Event(事件)#

import threading
import time
# Event:线程间简单通信
event = threading.Event()
def waiter(name):
print(f"{name} 等待事件...")
event.wait() # 阻塞直到 event.set()
print(f"{name} 收到事件,继续执行")
def setter():
time.sleep(2)
print("设置事件")
event.set()
# 启动等待者
for name in ["A", "B", "C"]:
threading.Thread(target=waiter, args=(name,)).start()
# 启动设置者
threading.Thread(target=setter).start()
# 2 秒后所有等待者同时继续执行

3.5 Condition(条件变量)#

import threading
import time
import random
# 生产者-消费者模式
class BoundedBuffer:
def __init__(self, capacity):
self.buffer = []
self.capacity = capacity
self.condition = threading.Condition()
def put(self, item):
with self.condition:
while len(self.buffer) >= self.capacity:
self.condition.wait() # 缓冲区满,等待
self.buffer.append(item)
self.condition.notify() # 通知消费者
def get(self):
with self.condition:
while not self.buffer:
self.condition.wait() # 缓冲区空,等待
item = self.buffer.pop(0)
self.condition.notify() # 通知生产者
return item
buffer = BoundedBuffer(5)
def producer(id):
for i in range(10):
item = f"产品-{id}-{i}"
buffer.put(item)
print(f"生产: {item}")
time.sleep(random.uniform(0.1, 0.5))
def consumer(id):
for _ in range(10):
item = buffer.get()
print(f" 消费({id}): {item}")
time.sleep(random.uniform(0.2, 0.8))
# 启动生产者和消费者
for i in range(2):
threading.Thread(target=producer, args=(i,)).start()
for i in range(3):
threading.Thread(target=consumer, args=(i,)).start()

四、Queue 线程安全队列#

4.1 基本队列#

import queue
import threading
import time
# Queue:线程安全的 FIFO 队列
q = queue.Queue(maxsize=10)
def producer():
for i in range(20):
q.put(f"任务-{i}")
print(f"生产: 任务-{i}")
time.sleep(0.1)
q.put(None) # 结束信号
def consumer(id):
while True:
item = q.get() # 阻塞获取
if item is None:
q.put(None) # 传递结束信号给其他消费者
break
print(f" 消费者-{id}: 处理 {item}")
time.sleep(0.3)
q.task_done() # 标记任务完成
# 启动
threading.Thread(target=producer).start()
for i in range(3):
threading.Thread(target=consumer, args=(i,)).start()

4.2 队列类型#

import queue
# FIFO 队列(先进先出)
fifo = queue.Queue()
fifo.put(1)
fifo.put(2)
print(fifo.get()) # 1
# LIFO 队列(后进先出,栈)
lifo = queue.LifoQueue()
lifo.put(1)
lifo.put(2)
print(lifo.get()) # 2
# 优先级队列
pq = queue.PriorityQueue()
pq.put((3, "低优先级"))
pq.put((1, "高优先级"))
pq.put((2, "中优先级"))
print(pq.get()[1]) # "高优先级"
print(pq.get()[1]) # "中优先级"
print(pq.get()[1]) # "低优先级"

4.3 线程池工作队列模式#

import queue
import threading
import time
import requests
class ThreadPool:
"""简易线程池"""
def __init__(self, num_threads):
self.tasks = queue.Queue()
self.threads = []
self.running = True
for _ in range(num_threads):
t = threading.Thread(target=self._worker)
t.daemon = True
t.start()
self.threads.append(t)
def _worker(self):
while self.running:
try:
func, args, callback = self.tasks.get(timeout=1)
result = func(*args)
if callback:
callback(result)
self.tasks.task_done()
except queue.Empty:
continue
def submit(self, func, *args, callback=None):
self.tasks.put((func, args, callback))
def shutdown(self):
self.running = False
for t in self.threads:
t.join()
# 使用
pool = ThreadPool(4)
def fetch(url):
response = requests.get(url)
return len(response.text)
def on_complete(result):
print(f"获取到 {result} 字节")
urls = ["https://httpbin.org/get"] * 5
for url in urls:
pool.submit(fetch, url, callback=on_complete)
time.sleep(5)
pool.shutdown()

五、multiprocessing 多进程#

5.1 创建进程#

import multiprocessing
import time
def worker(name, delay):
print(f"进程 {name} 开始")
time.sleep(delay)
print(f"进程 {name} 完成")
if __name__ == '__main__':
p1 = multiprocessing.Process(target=worker, args=("A", 2))
p2 = multiprocessing.Process(target=worker, args=("B", 3))
p1.start()
p2.start()
p1.join()
p2.join()
print("所有进程完成")

5.2 CPU 密集型任务对比#

import threading
import multiprocessing
import time
import math
def cpu_intensive(n):
"""CPU 密集型任务:计算质数"""
count = 0
for i in range(2, n):
is_prime = True
for j in range(2, int(math.sqrt(i)) + 1):
if i % j == 0:
is_prime = False
break
if is_prime:
count += 1
return count
# 单线程
start = time.time()
result1 = cpu_intensive(500_000)
result2 = cpu_intensive(500_000)
single_time = time.time() - start
print(f"单线程: {single_time:.2f}s")
# 多线程(受 GIL 限制,无加速)
start = time.time()
t1 = threading.Thread(target=cpu_intensive, args=(500_000,))
t2 = threading.Thread(target=cpu_intensive, args=(500_000,))
t1.start()
t2.start()
t1.join()
t2.join()
thread_time = time.time() - start
print(f"多线程: {thread_time:.2f}s")
# 多进程(真正并行,接近 2 倍加速)
if __name__ == '__main__':
start = time.time()
p1 = multiprocessing.Process(target=cpu_intensive, args=(500_000,))
p2 = multiprocessing.Process(target=cpu_intensive, args=(500_000,))
p1.start()
p2.start()
p1.join()
p2.join()
process_time = time.time() - start
print(f"多进程: {process_time:.2f}s")
# 结果示例:
# 单线程: 8.52s
# 多线程: 8.71s(无加速,甚至更慢)
# 多进程: 4.38s(接近 2 倍加速)

5.3 获取进程返回值#

import multiprocessing
def compute(x, y):
return x * y
if __name__ == '__main__':
# 方法1:使用 Queue
result_queue = multiprocessing.Queue()
def worker_with_queue(x, y, q):
q.put(compute(x, y))
p = multiprocessing.Process(
target=worker_with_queue,
args=(10, 20, result_queue)
)
p.start()
p.join()
print(result_queue.get()) # 200
# 方法2:使用 Pool(推荐)
with multiprocessing.Pool() as pool:
result = pool.apply(compute, (10, 20))
print(result) # 200

六、进程间通信#

6.1 Pipe(管道)#

import multiprocessing
def sender(conn):
conn.send("Hello from sender")
data = conn.recv()
print(f"Sender received: {data}")
conn.close()
if __name__ == '__main__':
parent_conn, child_conn = multiprocessing.Pipe()
p = multiprocessing.Process(target=sender, args=(child_conn,))
p.start()
print(parent_conn.recv()) # "Hello from sender"
parent_conn.send("Hello from parent")
p.join()

6.2 Queue(进程队列)#

import multiprocessing
import time
def producer(q):
for i in range(5):
q.put(f"产品-{i}")
print(f"生产: 产品-{i}")
time.sleep(0.5)
q.put(None) # 结束信号
def consumer(q):
while True:
item = q.get()
if item is None:
break
print(f"消费: {item}")
time.sleep(1)
if __name__ == '__main__':
q = multiprocessing.Queue(maxsize=10)
p1 = multiprocessing.Process(target=producer, args=(q,))
p2 = multiprocessing.Process(target=consumer, args=(q,))
p1.start()
p2.start()
p1.join()
p2.join()

6.3 Value 和 Array(共享内存)#

import multiprocessing
def increment_counter(counter, lock):
for _ in range(100_000):
with lock:
counter.value += 1
if __name__ == '__main__':
# 共享整数
counter = multiprocessing.Value('i', 0)
lock = multiprocessing.Lock()
processes = [
multiprocessing.Process(target=increment_counter, args=(counter, lock))
for _ in range(4)
]
for p in processes:
p.start()
for p in processes:
p.join()
print(f"最终值: {counter.value}") # 400000
# 共享数组
def modify_array(arr, lock):
for i in range(len(arr)):
with lock:
arr[i] += 1
if __name__ == '__main__':
arr = multiprocessing.Array('i', [0, 0, 0, 0, 0])
lock = multiprocessing.Lock()
processes = [
multiprocessing.Process(target=modify_array, args=(arr, lock))
for _ in range(3)
]
for p in processes:
p.start()
for p in processes:
p.join()
print(f"数组: {list(arr)}") # [3, 3, 3, 3, 3]

6.4 Manager(共享对象)#

import multiprocessing
def worker(d, key, value):
d[key] = value
if __name__ == '__main__':
with multiprocessing.Manager() as manager:
# 共享字典
shared_dict = manager.dict()
processes = []
for i in range(5):
p = multiprocessing.Process(
target=worker,
args=(shared_dict, f"key_{i}", f"value_{i}")
)
processes.append(p)
p.start()
for p in processes:
p.join()
print(dict(shared_dict))
# {'key_0': 'value_0', 'key_1': 'value_1', ...}
# Manager 还支持 list, dict, Namespace, Lock 等
shared_list = manager.list()
shared_list.append(1)

七、concurrent.futures(推荐)#

7.1 ThreadPoolExecutor#

from concurrent.futures import ThreadPoolExecutor, as_completed
import requests
# 线程池:IO 密集型任务
def fetch_url(url):
response = requests.get(url, timeout=10)
return url, response.status_code, len(response.text)
urls = [
"https://httpbin.org/get",
"https://httpbin.org/delay/1",
"https://httpbin.org/delay/2",
"https://httpbin.org/ip",
"https://httpbin.org/uuid",
]
# 方法1:submit + as_completed(灵活)
with ThreadPoolExecutor(max_workers=3) as executor:
futures = {executor.submit(fetch_url, url): url for url in urls}
for future in as_completed(futures):
url = futures[future]
try:
result = future.result()
print(f"{result[0]}: {result[1]} ({result[2]} bytes)")
except Exception as e:
print(f"{url} 错误: {e}")
# 方法2:map(简单,按顺序返回)
with ThreadPoolExecutor(max_workers=3) as executor:
results = executor.map(fetch_url, urls)
for result in results:
print(f"{result[0]}: {result[1]} ({result[2]} bytes)")

7.2 ProcessPoolExecutor#

from concurrent.futures import ProcessPoolExecutor, as_completed
import math
# 进程池:CPU 密集型任务
def is_prime(n):
if n < 2:
return False
for i in range(2, int(math.sqrt(n)) + 1):
if n % i == 0:
return False
return True
def count_primes(start, end):
count = 0
for i in range(start, end):
if is_prime(i):
count += 1
return count
if __name__ == '__main__':
# 将任务分成 4 块
ranges = [
(2, 250_000),
(250_000, 500_000),
(500_000, 750_000),
(750_000, 1_000_000),
]
with ProcessPoolExecutor(max_workers=4) as executor:
futures = {
executor.submit(count_primes, start, end): (start, end)
for start, end in ranges
}
total = 0
for future in as_completed(futures):
count = future.result()
total += count
print(f"区块 {futures[future]}: {count} 个质数")
print(f"总计: {total} 个质数")

7.3 回调函数#

from concurrent.futures import ThreadPoolExecutor
import requests
def fetch(url):
response = requests.get(url)
return response.json()
def on_success(future):
"""任务完成回调"""
try:
data = future.result()
print(f"成功: {data.get('url', 'unknown')}")
except Exception as e:
print(f"失败: {e}")
with ThreadPoolExecutor(max_workers=3) as executor:
future = executor.submit(fetch, "https://httpbin.org/get")
future.add_done_callback(on_success)
# 主线程可以继续做其他事
print("任务已提交")

7.4 统一接口切换#

from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
def task(n):
import time
time.sleep(1)
return n * n
# 只需改一行即可切换线程池/进程池
def run(executor_class, tasks):
with executor_class(max_workers=4) as executor:
results = list(executor.map(task, tasks))
return results
tasks = list(range(10))
# IO 密集型 → 用线程池
results = run(ThreadPoolExecutor, tasks)
print(results)
# CPU 密集型 → 用进程池
if __name__ == '__main__':
results = run(ProcessPoolExecutor, tasks)
print(results)

八、实战场景#

8.1 并发网页爬虫#

from concurrent.futures import ThreadPoolExecutor, as_completed
import requests
from bs4 import BeautifulSoup
import time
def crawl_page(url):
try:
response = requests.get(url, timeout=10)
soup = BeautifulSoup(response.text, 'html.parser')
title = soup.find('title')
return {
'url': url,
'status': response.status_code,
'title': title.text if title else 'N/A',
'length': len(response.text),
}
except Exception as e:
return {'url': url, 'error': str(e)}
def batch_crawl(urls, max_workers=10):
results = []
with ThreadPoolExecutor(max_workers=max_workers) as executor:
futures = {executor.submit(crawl_page, url): url for url in urls}
for future in as_completed(futures):
result = future.result()
results.append(result)
if 'error' not in result:
print(f"[{result['status']}] {result['title']} - {result['url']}")
return results
# 使用
urls = [f"https://httpbin.org/delay/{i % 3}" for i in range(20)]
start = time.time()
results = batch_crawl(urls, max_workers=10)
print(f"\n爬取 {len(urls)} 个页面,耗时: {time.time() - start:.2f}s")

8.2 并行数据处理#

from concurrent.futures import ProcessPoolExecutor
import time
def process_chunk(data_chunk):
"""处理数据块(CPU 密集型)"""
result = []
for item in data_chunk:
# 模拟计算密集型操作
value = sum(i * i for i in range(item))
result.append(value)
return result
def parallel_process(data, num_workers=4):
"""并行处理大数据集"""
# 分块
chunk_size = len(data) // num_workers
chunks = [
data[i:i + chunk_size]
for i in range(0, len(data), chunk_size)
]
# 并行处理
with ProcessPoolExecutor(max_workers=num_workers) as executor:
results = list(executor.map(process_chunk, chunks))
# 合并结果
return [item for chunk in results for item in chunk]
if __name__ == '__main__':
data = list(range(1000, 2000))
start = time.time()
result = parallel_process(data, num_workers=4)
print(f"并行处理 {len(data)} 项,耗时: {time.time() - start:.2f}s")

8.3 速率限制并发#

import threading
import time
import requests
from concurrent.futures import ThreadPoolExecutor
class RateLimiter:
"""令牌桶速率限制器"""
def __init__(self, rate, capacity=None):
self.rate = rate # 每秒生成的令牌数
self.capacity = capacity or rate
self.tokens = self.capacity
self.last_update = time.time()
self.lock = threading.Lock()
def acquire(self):
with self.lock:
now = time.time()
elapsed = now - self.last_update
self.tokens = min(
self.capacity,
self.tokens + elapsed * self.rate
)
self.last_update = now
if self.tokens >= 1:
self.tokens -= 1
return True
return False
def rate_limited_fetch(url, rate_limiter):
while not rate_limiter.acquire():
time.sleep(0.01)
response = requests.get(url)
return url, response.status_code
# 每秒最多 5 个请求
rate_limiter = RateLimiter(rate=5)
urls = [f"https://httpbin.org/get?i={i}" for i in range(20)]
with ThreadPoolExecutor(max_workers=10) as executor:
futures = [
executor.submit(rate_limited_fetch, url, rate_limiter)
for url in urls
]
for future in futures:
url, status = future.result()
print(f"{status} - {url}")

九、常见陷阱与最佳实践#

❌ 陷阱 1:竞态条件#

import threading
# ❌ 线程不安全
balance = 0
def transfer(amount):
global balance
# 以下操作非原子性
current = balance
time.sleep(0.001) # 模拟延迟
balance = current + amount
# ✅ 使用锁保护共享资源
balance = 0
lock = threading.Lock()
def safe_transfer(amount):
global balance
with lock:
current = balance
balance = current + amount

❌ 陷阱 2:死锁#

import threading
# ❌ 死锁:锁的获取顺序不一致
lock1 = threading.Lock()
lock2 = threading.Lock()
def task_a():
with lock1:
time.sleep(0.1)
with lock2: # 等待 lock2
print("A done")
def task_b():
with lock2:
time.sleep(0.1)
with lock1: # 等待 lock1 → 死锁
print("B done")
# ✅ 修复:统一锁的获取顺序
def task_a_fixed():
with lock1:
with lock2:
print("A done")
def task_b_fixed():
with lock1: # 先获取 lock1
with lock2: # 再获取 lock2
print("B done")

❌ 陷阱 3:守护线程中的资源泄漏#

import threading
# ❌ 守护线程可能被强制终止,导致资源未释放
def write_file():
with open("data.txt", "w") as f:
while True:
f.write("data\n")
time.sleep(1)
# daemon=True 的线程在主线程退出时会被强制终止
# 可能导致文件未正确关闭
# ✅ 使用非守护线程 + 优雅退出
def write_file_safe(stop_event):
with open("data.txt", "w") as f:
while not stop_event.is_set():
f.write("data\n")
f.flush()
time.sleep(1)
stop = threading.Event()
t = threading.Thread(target=write_file_safe, args=(stop,))
t.start()
# 优雅退出
stop.set()
t.join()

✅ 最佳实践#

原则说明
IO 密集用线程网络请求、文件读写
CPU 密集用进程计算、加密、图像处理
优先用 concurrent.futures统一 API,简化代码
避免共享状态使用 Queue 传递数据
锁要最小化只锁必要的代码段
统一锁顺序避免死锁
设置超时避免永久阻塞
使用上下文管理器自动释放资源
进程池注意序列化参数必须可 pickle

十、总结#

并发方案对比#

方案适用场景优势劣势
threadingIO 密集型轻量、共享内存GIL 限制
multiprocessingCPU 密集型真正并行内存开销大
concurrent.futures通用统一 API、简化代码灵活性略低
asyncio高并发 IO单线程高并发需要异步库支持

选型决策#

需要并发?
├── IO 密集型
│ ├── 简单场景 → ThreadPoolExecutor
│ ├── 高并发 → asyncio
│ └── 需要同步代码 → threading + Queue
├── CPU 密集型
│ ├── 简单并行 → ProcessPoolExecutor
│ ├── 大数据 → multiprocessing + SharedMemory
│ └── 数值计算 → NumPy(释放 GIL)
└── 混合型
└── ThreadPoolExecutor + ProcessPoolExecutor

Python 并发编程的核心是理解 GIL 的影响并选择正确的工具。IO 密集型用线程,CPU 密集型用进程,简单场景用 concurrent.futures。掌握同步原语和进程间通信,才能写出安全高效的并发程序。2026 年,concurrent.futures 已成为 Python 并发编程的首选方案,推荐优先使用。

Python 并发编程完全指南:threading / multiprocessing / concurrent.futures 深度解析与实战
https://971918.xyz/posts/python-guide/python-concurrency-guide/
作者
九所长
发布于
2026-07-22
许可协议
CC BY-NC-SA 4.0