Python并发编程入门:多线程与多进程的10大核心指南
【初识并发】
嘿,小伙伴们好!我是资深Python开发工程师老冉。今天要和大家聊一个超级硬核又实用的话题 - 并发编程。
💡 还记得你每次运行耗时任务时,程序像蜗牛一样慢吞吞的感觉吗?或者在处理大量IO操作时,CPU却闲得发慌?这些都是单线程程序的通病。
不用担心,今天我就教你几招,让你的Python程序"分身乘万",秒变并发达人!
【并发进阶之路】
1. 基础概念大拆解 🔸
首先我们要搞清楚几个重要概念:
• 进程:就像是一个独立的"小房间",有自己的资源和空间
• 线程:则像是房间里的"小精灵",共享房间的资源
📌 当我们启动Python程序时,就创建了一个进程,而在这个进程中,默认运行着一个主线程。
import threading
import multiprocessing
# 查看当前线程
print(f"当前线程名称: {threading.current_thread().name}")
# 查看CPU核心数
print(f"CPU核心数: {multiprocessing.cpu_count()}")
2. 多线程实战 🔸
让我们来看个实际例子,假设我们要同时下载多个文件:
import threading
import time
def download_file(filename):
print(f"开始下载{filename}")
time.sleep(2) # 模拟下载耗时
print(f"{filename}下载完成")
# 创建多个线程
threads = []
for i in range(3):
t = threading.Thread(target=download_file, args=(f"文件{i}",))
threads.append(t)
t.start()
# 等待所有线程完成
for t in threads:
t.join()
3. 进程池的强大威力 🔸
处理CPU密集型任务时,多进程更有优势:
from multiprocessing import Pool
def heavy_calculation(n):
return sum(i * i for i in range(n))
if __name__ == '__main__':
numbers = [10000000, 20000000, 30000000]
# 创建进程池
with Pool() as pool:
results = pool.map(heavy_calculation, numbers)
print(f"计算结果: {results}")
4. 锁机制保护共享资源 🔸
多个线程同时访问共享资源时,需要加锁保护:
import threading
counter = 0
lock = threading.Lock()
def increment():
global counter
with lock:
current = counter
time.sleep(0.1)
counter = current + 1
5. 生产者消费者模式 🔸
from queue import Queue
from threading import Thread
def producer(queue):
for i in range(5):
queue.put(f"数据{i}")
time.sleep(1)
def consumer(queue):
while True:
data = queue.get()
print(f"处理数据: {data}")
queue.task_done()
# 创建队列和线程
data_queue = Queue()
prod = Thread(target=producer, args=(data_queue,))
cons = Thread(target=consumer, args=(data_queue,))
6. 异步协程的优雅之道 🔸
协程是Python并发编程中的一大利器,特别适合IO密集型任务:
import asyncio
async def fetch_data(id):
print(f"开始获取数据{id}")
await asyncio.sleep(1) # 模拟IO操作
print(f"数据{id}获取完成")
return f"数据{id}"
async def main():
# 创建任务列表
tasks = [fetch_data(i) for i in range(3)]
# 并发执行所有任务
results = await asyncio.gather(*tasks)
print(f"所有结果: {results}")
# 运行协程
asyncio.run(main())
7. 线程池执行器 🔸
from concurrent.futures import ThreadPoolExecutor
import requests
def fetch_url(url):
response = requests.get(url)
return f"{url}: {len(response.content)} bytes"
urls = [
'http://example.com',
'http://python.org',
'http://github.com'
]
with ThreadPoolExecutor(max_workers=3) as executor:
results = executor.map(fetch_url, urls)
for result in results:
print(result)
8. 信号量控制并发数 🔸
import threading
import time
# 限制最多3个线程同时执行
semaphore = threading.Semaphore(3)
def access_resource(i):
with semaphore:
print(f"线程{i}开始访问资源")
time.sleep(2)
print(f"线程{i}释放资源")
# 创建10个线程
threads = [
threading.Thread(target=access_resource, args=(i,))
for i in range(10)
]
for t in threads:
t.start()
9. 事件通知机制 🔸
import threading
import time
event = threading.Event()
def wait_for_event():
print("等待事件发生...")
event.wait()
print("收到事件通知!")
def trigger_event():
time.sleep(3)
print("触发事件")
event.set()
# 创建并启动线程
t1 = threading.Thread(target=wait_for_event)
t2 = threading.Thread(target=trigger_event)
t1.start()
t2.start()
10. 条件变量实现同步 🔸
import threading
import time
condition = threading.Condition()
products = []
def producer():
with condition:
while len(products) >= 5:
condition.wait()
products.append('商品')
print(f"生产商品,当前库存: {len(products)}")
condition.notify()
def consumer():
with condition:
while len(products) == 0:
condition.wait()
products.pop()
print(f"消费商品,当前库存: {len(products)}")
condition.notify()
# 创建生产者和消费者线程
producers = [threading.Thread(target=producer) for _ in range(5)]
consumers = [threading.Thread(target=consumer) for _ in range(5)]
for p in producers:
p.start()
for c in consumers:
c.start()
【实战启示录】
📌 核心要点总结
• CPU密集型任务→多进程
• IO密集型任务→多线程或协程
• 大量小任务→线程池
• 资源受限场景→信号量
• 复杂同步需求→条件变量
💡 最佳实践提示:
1. 在选择并发方案时,要根据任务特性选择合适的方式
2. 共享资源操作时,切记加锁保护
3. 善用线程池和进程池来管理并发任务
4. 协程特别适合IO密集型的网络操作
🎉 经过这篇文章的学习,相信你已经掌握了并发编程的核心要点。如果你有任何问题,欢迎在评论区留言交流!让我们一起在Python的海洋里遨游,下期见!
🔍 延伸阅读:
• Python官方文档的threading模块
• Python官方文档的multiprocessing模块
• Python官方文档的asyncio模块