文章目录
- [第一部分:多线程 threading 使用教程](#第一部分:多线程 threading 使用教程)
-
- [1. 基础创建线程两种方式](#1. 基础创建线程两种方式)
- [2. 共享变量加锁解决数据错乱](#2. 共享变量加锁解决数据错乱)
- [3. 线程安全通信:queue队列](#3. 线程安全通信:queue队列)
- [4. 线程池(推荐大量并发场景)](#4. 线程池(推荐大量并发场景))
- [第二部分:多进程 multiprocessing 使用教程](#第二部分:多进程 multiprocessing 使用教程)
-
- 核心特点
- [1. 基础创建进程](#1. 基础创建进程)
- [2. 进程间数据通信](#2. 进程间数据通信)
-
- [方式1:multiprocessing.Queue 队列(多进程安全)](#方式1:multiprocessing.Queue 队列(多进程安全))
- 方式2:Manager共享变量(多进程共享数值、列表)
- [3. 进程池(CPU密集批量计算首选)](#3. 进程池(CPU密集批量计算首选))
- 第三部分:多线程与多进程场景选择标准
-
- [选用多线程 threading / ThreadPoolExecutor](#选用多线程 threading / ThreadPoolExecutor)
- [选用多进程 multiprocessing / ProcessPoolExecutor](#选用多进程 multiprocessing / ProcessPoolExecutor)
Python 实现并发两大标准库:
threading:多线程,适合IO密集(爬虫、文件读写、接口请求),轻量、共享内存,受GIL限制无法多核计算;multiprocessing:多进程,适合CPU密集(数值运算、图像处理、批量加密),独立内存,绕过GIL实现多核并行。
下文全部为可直接运行的完整示例,分模块讲解基础用法、数据通信、线程池/进程池实战,无冗余理论,侧重工程使用。
第一部分:多线程 threading 使用教程
1. 基础创建线程两种方式
方式1:函数式创建(日常开发最常用)
核心:threading.Thread(target=执行函数, args=参数元组)
start():启动线程join():主线程阻塞等待子线程完成
python
import threading
import time
def task(name, delay):
print(f"线程 {name} 开始执行")
time.sleep(delay) # 模拟IO阻塞
print(f"线程 {name} 执行完毕")
if __name__ == "__main__":
t1 = threading.Thread(target=task, args=("A", 2))
t2 = threading.Thread(target=task, args=("B", 1))
# 启动线程
t1.start()
t2.start()
# 等待线程结束再执行主线程后续代码
t1.join()
t2.join()
print("所有子线程运行完成")
方式2:继承Thread类自定义线程(复杂业务封装)
重写run()方法,线程启动后自动执行run内逻辑
python
import threading
import time
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} 结束")
if __name__ == "__main__":
t1 = MyThread("线程1", 2)
t2 = MyThread("线程2", 1)
t1.start()
t2.start()
t1.join()
t2.join()
print("自定义线程全部执行完毕")
2. 共享变量加锁解决数据错乱
多线程共享全局变量会产生竞态条件,使用threading.Lock互斥锁保证同一时间仅一个线程修改共享数据
python
import threading
count = 0
lock = threading.Lock()
def add_count():
global count
for _ in range(100000):
# with自动上锁、释放锁,无需手动release,避免死锁
with lock:
count += 1
if __name__ == "__main__":
thread_list = []
for i in range(5):
t = threading.Thread(target=add_count)
thread_list.append(t)
t.start()
# 等待全部线程执行完成
for t in thread_list:
t.join()
print("最终统计值:", count)
3. 线程安全通信:queue队列
不推荐直接全局变量传参,queue.Queue内置锁,生产者消费者标准方案
python
import threading
import queue
import time
q = queue.Queue(maxsize=10)
# 生产者:写入数据
def producer():
for i in range(5):
q.put(f"任务{i}")
print(f"生产:任务{i}")
time.sleep(0.2)
# 消费者:读取数据
def consumer():
while True:
data = q.get()
print(f"消费:{data}")
q.task_done()
time.sleep(0.3)
if __name__ == "__main__":
t_pro = threading.Thread(target=producer)
t_con = threading.Thread(target=consumer, daemon=True)
t_pro.start()
t_con.start()
t_pro.join()
q.join()
print("所有数据消费完成")
4. 线程池(推荐大量并发场景)
手动创建大量线程开销大,concurrent.futures.ThreadPoolExecutor自动管理线程数量
python
from concurrent.futures import ThreadPoolExecutor
import time
def spider(url):
print(f"正在请求:{url}")
time.sleep(1)
return f"{url} 请求完成"
if __name__ == "__main__":
url_list = ["baidu", "bing", "qq", "douyin"]
# 最大并发线程4个
with ThreadPoolExecutor(max_workers=4) as executor:
# 批量提交任务
results = executor.map(spider, url_list)
# 遍历结果
for res in results:
print(res)
第二部分:多进程 multiprocessing 使用教程
核心特点
- 每个进程拥有独立内存空间,默认不共享变量;
- 绕过GIL,多核CPU并行计算;
- 创建开销大于线程,通信需要专用工具(Queue、Pipe、Manager)。
1. 基础创建进程
用法和threading高度相似,multiprocessing.Process
python
import multiprocessing
import time
def calc_task(num):
print(f"进程 {num} 开始计算")
# 模拟CPU密集运算
res = sum(i for i in range(10000000))
print(f"进程 {num} 计算完成,结果:{res % 1000}")
if __name__ == "__main__":
# Windows系统必须写if __name__ == "__main__",否则无限递归创建进程
p1 = multiprocessing.Process(target=calc_task, args=(1,))
p2 = multiprocessing.Process(target=calc_task, args=(2,))
p1.start()
p2.start()
p1.join()
p2.join()
print("所有进程计算结束")
2. 进程间数据通信
进程内存隔离,普通全局变量无法互通,两种常用通信方式:
方式1:multiprocessing.Queue 队列(多进程安全)
python
import multiprocessing
def producer(q):
for i in range(3):
q.put(f"数据{i}")
def consumer(q):
while not q.empty():
data = q.get()
print("进程读取:", data)
if __name__ == "__main__":
q = multiprocessing.Queue()
p1 = multiprocessing.Process(target=producer, args=(q,))
p2 = multiprocessing.Process(target=consumer, args=(q,))
p1.start()
p1.join()
p2.start()
p2.join()
方式2:Manager共享变量(多进程共享数值、列表)
python
import multiprocessing
def add_num(share_num, lock):
for _ in range(10000):
with lock:
share_num.value += 1
if __name__ == "__main__":
# 创建进程管理器
manager = multiprocessing.Manager()
share_count = manager.Value("i", 0) # 共享整型变量
lock = manager.Lock()
p_list = []
for i in range(4):
p = multiprocessing.Process(target=add_num, args=(share_count, lock))
p_list.append(p)
p.start()
for p in p_list:
p.join()
print("多进程共享数值:", share_count.value)
3. 进程池(CPU密集批量计算首选)
ProcessPoolExecutor自动管理进程数量,充分利用多核
python
from concurrent.futures import ProcessPoolExecutor
def heavy_calc(n):
total = 0
for i in range(n):
total += i ** 2
return total
if __name__ == "__main__":
task_nums = [200000, 300000, 400000, 500000]
# 进程数默认等于CPU核心数
with ProcessPoolExecutor() as executor:
res = executor.map(heavy_calc, task_nums)
for r in res:
print("计算结果:", r)
第三部分:多线程与多进程场景选择标准
选用多线程 threading / ThreadPoolExecutor
- IO密集型任务:网络爬虫、HTTP接口请求、文件读写、数据库查询;
- 任务阻塞时间远大于计算时间,GIL会在IO等待时释放,并发提升明显;
- 需要轻量并发,资源占用低,大量任务也不会消耗过多内存。
选用多进程 multiprocessing / ProcessPoolExecutor
- CPU密集型任务:大数据循环计算、图片批量处理、视频解码、加密算法;
- 需要利用多核CPU,规避GIL限制,实现真正并行加速;
- 任务崩溃隔离,单个进程异常不会导致整个程序退出。