python 的asyncio与multiporcess
在 Python 中,协程(asyncio)、多线程(multithreading)和多进程(multiprocessing)是实现并发和并行的三种主要方式。它们各有优劣,适用于不同场景。以下是它们的比较、使用实例和适用场景。
🔄 一、概述
1. 协程(Coroutines)
- 基于事件循环(
asyncio)。 - 协作式多任务:协程通过
await关键字主动让出控制权。 - 轻量级:比线程更轻,适合高并发 I/O 操作。
- 需要异步库支持(如
aiohttp,asyncpg)。
2. 多线程(Multithreading)
- 抢占式多任务:由操作系统调度。
- 共享内存:线程间通信简单,但容易引发竞争条件。
- 受 GIL(全局解释器锁)限制:Python 中线程无法真正并行执行 CPU 密集型任务。
3. 多进程(Multiprocessing)
- 独立内存空间:每个进程拥有独立的 Python 解释器和内存。
- 绕过 GIL:适合 CPU 密集型任务。
- 进程间通信复杂:需要使用
Queue,Pipe或Manager。
📊 二、对比表
| 特性 | 协程(asyncio) |
多线程(threading) |
多进程(multiprocessing) |
|---|---|---|---|
| 并发模型 | 协作式(await) |
抢占式(OS 调度) | 抢占式(OS 调度) |
| 并行性 | 单线程,无法并行 | 单线程(受 GIL 限制) | 多线程,可并行 |
| 内存占用 | 极低(轻量) | 中等(共享内存) | 高(独立内存) |
| 适合场景 | I/O 密集型(如网络请求) | I/O 密集型(少量线程) | CPU 密集型 |
| 通信/同步 | asyncio.Queue |
threading.Lock, threading.Event |
Queue, Pipe, Manager |
| 异步依赖 | 需要异步库(如 aiohttp) |
可使用同步库 | 可使用同步库 |
| 线程/进程数 | 可支持数万协程 | 通常数百线程 | 通常几十进程 |
🧪 三、使用实例
1. 协程(asyncio)示例
import asyncio
async def fetch(url):
print(f"Fetching {url}")
await asyncio.sleep(1)
print(f"Done {url}")
async def main():
tasks = [fetch(f"URL-{i}") for i in range(5)]
await asyncio.gather(*tasks)
asyncio.run(main())
2. 多线程(threading)示例
import threading
import time
def task(name):
time.sleep(1)
print(f"Thread {name} done")
threads = [threading.Thread(target=task, args=(i,)) for i in range(5)]
for t in threads:
t.start()
for t in threads:
t.join()
3. 多进程(multiprocessing)示例
from multiprocessing import Process
import time
def task(name):
time.sleep(1)
print(f"Process {name} done")
if __name__ == "__main__":
processes = [Process(target=task, args=(i,)) for i in range(5)]
for p in processes:
p.start()
for p in processes:
p.join()
🎯 四、适用场景
| 场景 | 推荐方式 | 说明 |
|---|---|---|
| I/O 密集型(大量并发) | asyncio |
协程轻量,适合高并发网络请求、异步任务。 |
| I/O 密集型(少量线程) | threading |
简单易用,适合少量线程的并发 I/O 操作。 |
| CPU 密集型(并行计算) | multiprocessing |
绕过 GIL,适合图像处理、科学计算等任务。 |
| GUI 应用 + 后台任务 | threading 或 asyncio |
threading 更适合传统 GUI 框架,asyncio 更适合现代异步框架(如 PyQt5)。 |
| 分布式任务调度 | multiprocessing + concurrent.futures |
适合构建分布式计算框架。 |
⚠️ 五、潜在问题
| 问题 | 说明 |
|---|---|
| 协程阻塞事件循环 | 若在协程中调用 time.sleep 而非 asyncio.sleep,会阻塞整个事件循环。 |
| 线程竞争条件 | 多线程共享内存,需使用锁(Lock, Semaphore)来避免资源竞争。 |
| 进程间通信复杂 | multiprocessing.Queue 和 Manager 可用于跨进程通信,但性能较低。 |
| GIL 限制 | threading 受 GIL 影响,无法真正并行执行 CPU 密集型任务。 |
📌 六、总结
| 选择建议 | 说明 |
|---|---|
| 高并发 I/O 操作(如 Web 爬虫、API 调用) | 优先使用 asyncio。 |
| 少量线程的并发 I/O(如 GUI 后台任务) | 使用 threading。 |
| CPU 密集型任务(如图像处理、机器学习) | 使用 multiprocessing。 |
| 需要异步编程模型 | 使用 asyncio,但需确保依赖库支持异步。 |
在 Python 的多进程编程中,multiprocessing.Queue、Manager 和 concurrent.futures.ProcessPoolExecutor 是三种常用的工具,用于实现进程间通信、共享状态和任务并行执行。它们各自适用于不同的场景,下面将分别展示使用这些工具的示例,并说明其适用场景。
🧱 一、使用 multiprocessing.Queue 实现进程间通信
multiprocessing.Queue 是一个线程和进程安全的队列,适合用于实现生产者-消费者模型,即一个进程生成任务,多个进程消费任务。
示例:任务队列
from multiprocessing import Process, Queue
import time
def worker(queue):
while True:
task = queue.get()
if task is None: # 任务结束标识
break
print(f"Processing: {task}")
time.sleep(0.5)
def main():
queue = Queue()
# 启动多个工作进程
workers = [Process(target=worker, args=(queue,)) for _ in range(3)]
for w in workers:
w.start()
# 添加任务
for i in range(10):
queue.put(f"Task-{i}")
# 发送结束信号
for _ in workers:
queue.put(None)
# 等待所有工作进程完成
for w in workers:
w.join()
if __name__ == "__main__":
main()
说明:
worker()是消费者函数,不断从队列中取出任务。queue.get()是阻塞的,直到有任务到来或遇到None。- 适用于任务队列、任务分发等场景。
🌐 二、使用 Manager 实现共享状态
Manager 提供了一个服务器进程,允许在多个进程中共享对象(如列表、字典、值等),适用于需要共享状态的场景。
示例:共享状态管理
from multiprocessing import Process, Manager
import time
def worker(shared_dict, name):
shared_dict[name] = f"Processed by {name}"
time.sleep(0.5)
def main():
with Manager() as manager:
shared_dict = manager.dict() # 创建共享字典
processes = []
for i in range(5):
p = Process(target=worker, args=(shared_dict, f"Worker-{i}"))
processes.append(p)
p.start()
for p in processes:
p.join()
print("Shared Dict:", shared_dict)
if __name__ == "__main__":
main()
说明:
- 使用
manager.dict()创建共享字典。 - 每个进程可以修改共享字典。
- 适用于共享状态、数据共享等场景。
🧠 三、使用 concurrent.futures.ProcessPoolExecutor 并行执行任务
ProcessPoolExecutor 是 concurrent.futures 模块中用于管理进程池的高级接口,适合用于并行计算密集型任务。
示例:并行计算平方数
from concurrent.futures import ProcessPoolExecutor
import time
def square(x):
time.sleep(0.5)
return x * x
def main():
with ProcessPoolExecutor(max_workers=4) as executor:
results = executor.map(square, range(10))
for result in results:
print(f"Result: {result}")
if __name__ == "__main__":
main()
说明:
executor.map()将任务分发给进程池。- 适用于批量任务并行处理、CPU 密集型任务。
- 无需手动管理进程和队列。
🧩 四、综合示例:构建一个简易的 Worker 集群
结合 Queue 和 Manager,我们可以实现一个简单的 Worker 集群模型,主进程分发任务,多个 Worker 进程处理任务,并通过共享状态收集结果。
from multiprocessing import Process, Queue, Manager
import time
def worker(queue, results):
while True:
task = queue.get()
if task is None:
break
print(f"Processing: {task}")
results[task] = task * task
time.sleep(0.5)
def main():
with Manager() as manager:
queue = Queue()
results = manager.dict()
# 启动多个工作进程
workers = [Process(target=worker, args=(queue, results)) for _ in range(3)]
for w in workers:
w.start()
# 添加任务
for i in range(10):
queue.put(i)
# 发送结束信号
for _ in workers:
queue.put(None)
# 等待所有工作进程完成
for w in workers:
w.join()
print("Final Results:", results)
if __name__ == "__main__":
main()
📌 五、总结与适用场景
| 工具 | 适用场景 | 特点 |
|---|---|---|
multiprocessing.Queue |
任务队列、生产者-消费者模型 | 简单、高效、适用于任务分发 |
Manager |
共享状态、数据共享 | 支持字典、列表等共享对象,适合状态同步 |
ProcessPoolExecutor |
并行执行函数、批量计算任务 | 高级接口,适合 CPU 密集型任务并行处理 |
📚 参考资料
- Python multiprocessing.Queue 官方文档
- Python multiprocessing.Manager 官方文档
- concurrent.futures.ProcessPoolExecutor 官方文档
通过以上示例,你可以根据实际需求选择合适的工具来构建多进程应用。


浙公网安备 33010602011771号