Python29_并发编程
### 文章目录
- [Python29_并发编程](#文章目录 Python29_并发编程 @[toc] 基本概念 1 并发 vs 并行 2 Python 的并发模型 多线程编程 1 基本使用 2 线程同步 3 线程间通信 多进程编程 1 基本使用 2 进程池 3 进程间通信 异步IO(asyncio) 1 基本概念 2 基本使用 3 高级特性 并发编程选择指南 实际应用示例 1 并发下载器 2 并行计算 常见问题)
- [@[toc]](#文章目录 Python29_并发编程 @[toc] 基本概念 1 并发 vs 并行 2 Python 的并发模型 多线程编程 1 基本使用 2 线程同步 3 线程间通信 多进程编程 1 基本使用 2 进程池 3 进程间通信 异步IO(asyncio) 1 基本概念 2 基本使用 3 高级特性 并发编程选择指南 实际应用示例 1 并发下载器 2 并行计算 常见问题)
- [基本概念](#文章目录 Python29_并发编程 @[toc] 基本概念 1 并发 vs 并行 2 Python 的并发模型 多线程编程 1 基本使用 2 线程同步 3 线程间通信 多进程编程 1 基本使用 2 进程池 3 进程间通信 异步IO(asyncio) 1 基本概念 2 基本使用 3 高级特性 并发编程选择指南 实际应用示例 1 并发下载器 2 并行计算 常见问题)
- [1 并发 vs 并行](#文章目录 Python29_并发编程 @[toc] 基本概念 1 并发 vs 并行 2 Python 的并发模型 多线程编程 1 基本使用 2 线程同步 3 线程间通信 多进程编程 1 基本使用 2 进程池 3 进程间通信 异步IO(asyncio) 1 基本概念 2 基本使用 3 高级特性 并发编程选择指南 实际应用示例 1 并发下载器 2 并行计算 常见问题)
- [2 Python 的并发模型](#文章目录 Python29_并发编程 @[toc] 基本概念 1 并发 vs 并行 2 Python 的并发模型 多线程编程 1 基本使用 2 线程同步 3 线程间通信 多进程编程 1 基本使用 2 进程池 3 进程间通信 异步IO(asyncio) 1 基本概念 2 基本使用 3 高级特性 并发编程选择指南 实际应用示例 1 并发下载器 2 并行计算 常见问题)
- [多线程编程](#文章目录 Python29_并发编程 @[toc] 基本概念 1 并发 vs 并行 2 Python 的并发模型 多线程编程 1 基本使用 2 线程同步 3 线程间通信 多进程编程 1 基本使用 2 进程池 3 进程间通信 异步IO(asyncio) 1 基本概念 2 基本使用 3 高级特性 并发编程选择指南 实际应用示例 1 并发下载器 2 并行计算 常见问题)
- [1 基本使用](#文章目录 Python29_并发编程 @[toc] 基本概念 1 并发 vs 并行 2 Python 的并发模型 多线程编程 1 基本使用 2 线程同步 3 线程间通信 多进程编程 1 基本使用 2 进程池 3 进程间通信 异步IO(asyncio) 1 基本概念 2 基本使用 3 高级特性 并发编程选择指南 实际应用示例 1 并发下载器 2 并行计算 常见问题)
- [2 线程同步](#文章目录 Python29_并发编程 @[toc] 基本概念 1 并发 vs 并行 2 Python 的并发模型 多线程编程 1 基本使用 2 线程同步 3 线程间通信 多进程编程 1 基本使用 2 进程池 3 进程间通信 异步IO(asyncio) 1 基本概念 2 基本使用 3 高级特性 并发编程选择指南 实际应用示例 1 并发下载器 2 并行计算 常见问题)
- [3 线程间通信](#文章目录 Python29_并发编程 @[toc] 基本概念 1 并发 vs 并行 2 Python 的并发模型 多线程编程 1 基本使用 2 线程同步 3 线程间通信 多进程编程 1 基本使用 2 进程池 3 进程间通信 异步IO(asyncio) 1 基本概念 2 基本使用 3 高级特性 并发编程选择指南 实际应用示例 1 并发下载器 2 并行计算 常见问题)
- [多进程编程](#文章目录 Python29_并发编程 @[toc] 基本概念 1 并发 vs 并行 2 Python 的并发模型 多线程编程 1 基本使用 2 线程同步 3 线程间通信 多进程编程 1 基本使用 2 进程池 3 进程间通信 异步IO(asyncio) 1 基本概念 2 基本使用 3 高级特性 并发编程选择指南 实际应用示例 1 并发下载器 2 并行计算 常见问题)
- [1 基本使用](#文章目录 Python29_并发编程 @[toc] 基本概念 1 并发 vs 并行 2 Python 的并发模型 多线程编程 1 基本使用 2 线程同步 3 线程间通信 多进程编程 1 基本使用 2 进程池 3 进程间通信 异步IO(asyncio) 1 基本概念 2 基本使用 3 高级特性 并发编程选择指南 实际应用示例 1 并发下载器 2 并行计算 常见问题)
- [2 进程池](#文章目录 Python29_并发编程 @[toc] 基本概念 1 并发 vs 并行 2 Python 的并发模型 多线程编程 1 基本使用 2 线程同步 3 线程间通信 多进程编程 1 基本使用 2 进程池 3 进程间通信 异步IO(asyncio) 1 基本概念 2 基本使用 3 高级特性 并发编程选择指南 实际应用示例 1 并发下载器 2 并行计算 常见问题)
- [3 进程间通信](#文章目录 Python29_并发编程 @[toc] 基本概念 1 并发 vs 并行 2 Python 的并发模型 多线程编程 1 基本使用 2 线程同步 3 线程间通信 多进程编程 1 基本使用 2 进程池 3 进程间通信 异步IO(asyncio) 1 基本概念 2 基本使用 3 高级特性 并发编程选择指南 实际应用示例 1 并发下载器 2 并行计算 常见问题)
- [异步IO(asyncio)](#文章目录 Python29_并发编程 @[toc] 基本概念 1 并发 vs 并行 2 Python 的并发模型 多线程编程 1 基本使用 2 线程同步 3 线程间通信 多进程编程 1 基本使用 2 进程池 3 进程间通信 异步IO(asyncio) 1 基本概念 2 基本使用 3 高级特性 并发编程选择指南 实际应用示例 1 并发下载器 2 并行计算 常见问题)
- [1 基本概念](#文章目录 Python29_并发编程 @[toc] 基本概念 1 并发 vs 并行 2 Python 的并发模型 多线程编程 1 基本使用 2 线程同步 3 线程间通信 多进程编程 1 基本使用 2 进程池 3 进程间通信 异步IO(asyncio) 1 基本概念 2 基本使用 3 高级特性 并发编程选择指南 实际应用示例 1 并发下载器 2 并行计算 常见问题)
- [2 基本使用](#文章目录 Python29_并发编程 @[toc] 基本概念 1 并发 vs 并行 2 Python 的并发模型 多线程编程 1 基本使用 2 线程同步 3 线程间通信 多进程编程 1 基本使用 2 进程池 3 进程间通信 异步IO(asyncio) 1 基本概念 2 基本使用 3 高级特性 并发编程选择指南 实际应用示例 1 并发下载器 2 并行计算 常见问题)
- [3 高级特性](#文章目录 Python29_并发编程 @[toc] 基本概念 1 并发 vs 并行 2 Python 的并发模型 多线程编程 1 基本使用 2 线程同步 3 线程间通信 多进程编程 1 基本使用 2 进程池 3 进程间通信 异步IO(asyncio) 1 基本概念 2 基本使用 3 高级特性 并发编程选择指南 实际应用示例 1 并发下载器 2 并行计算 常见问题)
- [并发编程选择指南](#文章目录 Python29_并发编程 @[toc] 基本概念 1 并发 vs 并行 2 Python 的并发模型 多线程编程 1 基本使用 2 线程同步 3 线程间通信 多进程编程 1 基本使用 2 进程池 3 进程间通信 异步IO(asyncio) 1 基本概念 2 基本使用 3 高级特性 并发编程选择指南 实际应用示例 1 并发下载器 2 并行计算 常见问题)
- [实际应用示例](#文章目录 Python29_并发编程 @[toc] 基本概念 1 并发 vs 并行 2 Python 的并发模型 多线程编程 1 基本使用 2 线程同步 3 线程间通信 多进程编程 1 基本使用 2 进程池 3 进程间通信 异步IO(asyncio) 1 基本概念 2 基本使用 3 高级特性 并发编程选择指南 实际应用示例 1 并发下载器 2 并行计算 常见问题)
- [1 并发下载器](#文章目录 Python29_并发编程 @[toc] 基本概念 1 并发 vs 并行 2 Python 的并发模型 多线程编程 1 基本使用 2 线程同步 3 线程间通信 多进程编程 1 基本使用 2 进程池 3 进程间通信 异步IO(asyncio) 1 基本概念 2 基本使用 3 高级特性 并发编程选择指南 实际应用示例 1 并发下载器 2 并行计算 常见问题)
- [2 并行计算](#文章目录 Python29_并发编程 @[toc] 基本概念 1 并发 vs 并行 2 Python 的并发模型 多线程编程 1 基本使用 2 线程同步 3 线程间通信 多进程编程 1 基本使用 2 进程池 3 进程间通信 异步IO(asyncio) 1 基本概念 2 基本使用 3 高级特性 并发编程选择指南 实际应用示例 1 并发下载器 2 并行计算 常见问题)
- [常见问题](#文章目录 Python29_并发编程 @[toc] 基本概念 1 并发 vs 并行 2 Python 的并发模型 多线程编程 1 基本使用 2 线程同步 3 线程间通信 多进程编程 1 基本使用 2 进程池 3 进程间通信 异步IO(asyncio) 1 基本概念 2 基本使用 3 高级特性 并发编程选择指南 实际应用示例 1 并发下载器 2 并行计算 常见问题)
并发编程 是现代软件开发中提高程序性能的重要手段。Python提供了多种并发编程方式,包括多线程、多进程和异步IO。
基本概念
1 并发 vs 并行
-
并发(Concurrency): 多个任务交替执行,看起来像是同时运行
-
并行(Parallelism): 多个任务真正同时执行,需要多核CPU支持
2 Python 的并发模型
-
I/O密集型任务: 适合使用多线程或异步IO
-
CPU密集型任务: 适合使用多进程
多线程编程
Python通过threading模块提供线程支持,但由于GIL(全局 解释器 锁)的存在,多线程不适合CPU密集型任务。
1 基本使用
python
import threading
import time
def task(name):
print(f"任务 {name} 开始")
time.sleep(2) # 模拟I/O操作
print(f"任务 {name} 完成")
# 创建线程
threads = []
for i in range(3):
t = threading.Thread(target=task, args=(f"Thread-{i}",))
threads.append(t)
t.start()
# 等待所有线程完成
for t in threads:
t.join()
print("所有任务完成")
2 线程同步
- 使用锁Lock/RLock
python
# 使用锁Lock/RLock
import threading
import time
counter = 0
lock = threading.Lock()
def increment():
global counter
for _ in range(100000):
with lock: # 自动获取和释放锁
counter += 1
if __name__ == '__main__':
thread_num = 5
print(f"{thread_num}个线程,开始时间: {time.time():.2f}")
threads = []
for _ in range(thread_num):
t = threading.Thread(target=increment)
threads.append(t)
t.start()
for t in threads:
t.join()
print(f"最终计数器值: {counter}") # 应该是500000
print(f"{thread_num}个线程,结束时间: {time.time():.2f}")
- 使用Semaphore信号量
- 注意:如果信号量不等于1,还是不能解决并发导致的【不安全的数据类型操作】问题
python
# 使用Semaphore信号量
import threading
import time
counter = 0
lock = threading.Lock()
def increment(thread_name):
global counter
for _ in range(20):
with semaphore: # 自动获取和释放锁
print(f"{thread_name} 正在使用资源 ")
counter += 1
print(f"{thread_name} 释放资源 ")
if __name__ == '__main__':
# 使用信号量(如果信号量不等于1,还是不能解决并发导致的【不安全的数据类型操作】问题)
semaphore = threading.Semaphore(3) # 最多3个线程同时访问
thread_num = 10
threads = []
print(f"{thread_num}个线程,开始时间: {time.time():.2f}")
for i in range(thread_num):
t = threading.Thread(target=increment, args=(f"ThreadName-{i}",))
threads.append(t)
t.start()
for t in threads:
t.join()
print(f"最终计数器值: {counter}") # 应该是500000
print(f"{thread_num}个线程,结束时间: {time.time():.2f}")
3 线程间通信
python
# 使用队列
import queue
def producer(q):
for i in range(5):
print(f"生产物品 {i}")
q.put(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)
q = queue.Queue()
threading.Thread(target=producer, args=(q,)).start()
threading.Thread(target=consumer, args=(q,)).start()
多进程编程
多进程可以绕过GIL限制,适合CPU密集型任务,但进程间通信开销较大。
1 基本使用
python
from multiprocessing import Process
import os
def cpu_bound_task(n):
print(f"进程 {os.getpid()} 计算 {n} 的平方")
return n * n
if __name__ == '__main__':
processes = []
for i in range(4):
p = Process(target=cpu_bound_task, args=(i,))
processes.append(p)
p.start()
for p in processes:
p.join()
2 进程池
python
from multiprocessing import Pool
def square(x):
return x * x
if __name__ == '__main__':
with Pool(4) as pool: # 4个工作进程
# map方法
results = pool.map(square, range(10))
print(results) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# apply_async方法
result = pool.apply_async(square, (10,))
print(result.get()) # 100
3 进程间通信
python
from multiprocessing import Process, Queue
def worker(q):
while True:
item = q.get()
if item is None:
break
print(f"处理: {item}")
if __name__ == '__main__':
q = Queue()
p = Process(target=worker, args=(q,))
p.start()
for i in range(5):
q.put(i)
q.put(None) # 结束信号
p.join()
异步IO(asyncio)
asyncio是Python3.4引入的 标准库 ,适合I/O密集型任务,使用单线程实现高并发。
1 基本概念
-
协程(Coroutine) : 使用
async def定义的函数 -
事件循环(Event Loop): 协程的调度器
-
Future/Task: 表示异步操作的结果
2 基本使用
python
import asyncio
async def fetch_data(url):
print(f"开始获取 {url}")
await asyncio.sleep(2) # 模拟I/O操作
print(f"完成获取 {url}")
return f"{url} 的数据"
async def main():
# 顺序执行
result1 = await fetch_data("url1")
result2 = await fetch_data("url2")
print(result1, result2)
# 并发执行
task1 = asyncio.create_task(fetch_data("url3"))
task2 = asyncio.create_task(fetch_data("url4"))
await task1
await task2
# 使用gather
results = await asyncio.gather(
fetch_data("url5"),
fetch_data("url6"),
fetch_data("url7")
)
print(results)
asyncio.run(main())
3 高级特性
python
# 超时控制
async def slow_operation():
await asyncio.sleep(5)
return "完成"
async def main():
try:
result = await asyncio.wait_for(slow_operation(), timeout=3.0)
except asyncio.TimeoutError:
print("操作超时")
# 事件循环控制
async def periodic_task():
while True:
print("执行周期性任务")
await asyncio.sleep(1)
async def main():
task = asyncio.create_task(periodic_task())
await asyncio.sleep(5)
task.cancel()
try:
await task
except asyncio.CancelledError:
print("任务已取消")
并发编程选择指南
| 方法 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 多线程 | I/O密集型,GUI应用 | 轻量级,共享内存方便 | 受GIL限制,不适合CPU密集型 |
| 多进程 | CPU密集型任务 | 绕过GIL,利用多核 | 内存开销大,进程间通信复杂 |
| 异步IO | 高并发I/O操作,网络应用 | 高效,单线程高并发 | 需要特殊库支持,学习曲线陡峭 |
实际应用示例
1 并发下载器
python
import aiohttp
import asyncio
async def download(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
content = await response.read()
print(f"下载 {url} 完成,长度: {len(content)}")
return content
async def main():
urls = [
'https://www.python.org',
'https://www.google.com',
'https://www.github.com'
]
tasks = [download(url) for url in urls]
await asyncio.gather(*tasks)
asyncio.run(main())
2 并行计算
python
from multiprocessing import Pool
import math
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
if __name__ == '__main__':
numbers = range(1000000, 1000100)
with Pool(4) as pool:
results = pool.map(is_prime, numbers)
primes = [n for n, prime in zip(numbers, results) if prime]
print(f"找到 {len(primes)} 个质数")
常见问题
-
GIL限制:
-
使用多进程代替多线程处理CPU密集型任务
-
使用C扩展释放GIL
-
-
死锁问题:
-
按固定顺序获取锁
-
使用带超时的锁
-
-
资源竞争:
-
使用线程安全的数据结构
-
尽量减少共享状态
-
-
协程阻塞:
-
避免在协程中使用阻塞I/O
-
使用专门的异步库(aiohttp, asyncpg等)
-
通过合理选择并发模型并正确实现,可以显著提高Python程序的性能,特别是在处理I/O密集型或CPU密集型任务时。