Python 并发编程:多线程、多进程与异步编程详解
并发编程是提升程序性能的关键技术。Python 提供了多线程、多进程、异步编程三种并发模型,各有适用场景。本文深入解析三种模型的原理与实践。
一、并发 vs 并行
并发:多个任务交替执行,宏观上同时进行,微观上串行。
并行:多个任务真正同时执行,需要多核 CPU 支持。
由于 GIL(全局解释器锁)的存在,Python 多线程无法利用多核实现真正的并行,但在 I/O 密集型场景仍然有效。
二、多线程编程
2.1 基本使用
import threading
import time
def task(name):
print(f"开始任务: name")
time.sleep(2)
print(f"完成任务: name")
# 创建线程
t1 = threading.Thread(target=task, args=("A",))
t2 = threading.Thread(target=task, args=("B",))
# 启动线程
t1.start()
t2.start()
# 等待完成
t1.join()
t2.join()
2.2 线程池
from concurrent.futures import ThreadPoolExecutor
import time
def download(url):
time.sleep(1)
return f"下载完成: url"
urls = ["url1", "url2", "url3", "url4", "url5"]
with ThreadPoolExecutor(max_workers=3) as executor:
results = executor.map(download, urls)
for result in results:
print(result)
2.3 线程同步
import threading
counter = 0
lock = threading.Lock()
def increment():
global counter
for _ in range(100000):
with lock:
counter += 1
threads = [threading.Thread(target=increment) for _ in range(10)]
for t in threads:
t.start()
for t in threads:
t.join()
print(f"最终结果: counter")
三、多进程编程
3.1 基本使用
from multiprocessing import Process, Pool
import os
def task(name):
print(f"进程 os.getpid(): name")
# 创建进程
p1 = Process(target=task, args=("A",))
p2 = Process(target=task, args=("B",))
p1.start()
p2.start()
p1.join()
p2.join()
3.2 进程池
from multiprocessing import Pool
def cpu_intensive(n):
return sum(i * i for i in range(n))
if __name__ == "__main__":
numbers = [10000000, 20000000, 30000000, 40000000]
with Pool(processes=4) as pool:
results = pool.map(cpu_intensive, numbers)
print(results)
3.3 进程间通信
from multiprocessing import Process, Queue, Manager
def producer(queue):
for i in range(10):
queue.put(i)
queue.put(None) # 结束信号
def consumer(queue):
while True:
item = queue.get()
if item is None:
break
print(f"消费: item")
if __name__ == "__main__":
queue = Queue()
p1 = Process(target=producer, args=(queue,))
p2 = Process(target=consumer, args=(queue,))
p1.start()
p2.start()
p1.join()
p2.join()
四、异步编程
4.1 asyncio 基础
import asyncio
async def fetch_data(url):
print(f"开始获取: url")
await asyncio.sleep(1)
return f"数据: url"
async def main():
tasks = [
fetch_data("url1"),
fetch_data("url2"),
fetch_data("url3"),
]
results = await asyncio.gather(*tasks)
print(results)
asyncio.run(main())
4.2 异步 HTTP 请求
import asyncio
import aiohttp
async def fetch(session, url):
async with session.get(url) as response:
return await response.text()
async def main():
urls = ["http://example.com"] * 10
async with aiohttp.ClientSession() as session:
tasks = [fetch(session, url) for url in urls]
results = await asyncio.gather(*tasks)
print(f"获取了 len(results) 个页面")
asyncio.run(main())
4.3 异步生成器
import asyncio
async def async_range(n):
for i in range(n):
await asyncio.sleep(0.1)
yield i
async def main():
async for num in async_range(5):
print(num)
asyncio.run(main())
五、选择指南
CPU 密集型:使用多进程,绕过 GIL 限制。
I/O 密集型:使用多线程或异步,推荐异步。
混合型:多进程 + 异步,进程池处理计算,协程处理 I/O。
六、最佳实践
1. 避免共享状态,使用消息传递
2. 合理设置并发数,避免资源耗尽
3. 注意异常处理,避免静默失败
4. 使用上下文管理器确保资源释放
5. 性能测试,选择最优方案
七、总结
Python 并发编程三种模型各有优劣。多线程适合 I/O 密集型,多进程适合 CPU 密集型,异步编程是现代 Python 的推荐方式。理解它们的原理和适用场景,才能选择正确的方案。
本文链接:https://www.kkkliao.cn/?id=778 转载需授权!
版权声明:本文由廖万里的博客发布,如需转载请注明出处。



手机流量卡
免费领卡
号卡合伙人
产品服务
关于本站
