python中并发执行(多线程执行的应用)
·
python中并发代码执行
1.asyncio.gather() —— 统一收集结果
import asyncio
async def task(name: str, delay: int, fail: bool = False) -> str:
await asyncio.sleep(delay)
if fail:
raise ValueError(f"{name} 出错了")
return f"{name} 完成"
async def main():
# gather:等待所有任务,统一返回结果
results = await asyncio.gather(
task("A", 1),
task("B", 2),
task("C", 3),
return_exceptions=True # 把异常作为结果返回,而不是抛出
)
for i, r in enumerate(results):
if isinstance(r, Exception):
print(f"任务 {i} 失败:{r}")
else:
print(f"任务 {i} 成功:{r}")
asyncio.run(main())
# 任务 A 成功:A 完成
# 任务 B 成功:B 完成
# 任务 C 成功:C 完成
2-示例2
import asyncio
async def task(name: str, fail: bool = False):
await asyncio.sleep(1)
if fail:
raise ValueError(f"{name} 失败")
return f"{name} 成功"
async def main():
tasks = [
task("A", False),
task("B", True), # 这个会失败
task("C", False),
]
# 方式1:return_exceptions=True(推荐)
results = await asyncio.gather(*tasks, return_exceptions=True)
for r in results:
if isinstance(r, Exception):
print(f"❌ {r}")
else:
print(f"✅ {r}")
asyncio.run(main())
示例3
import asyncio
async def safe_task(name: str) -> str:
try:
await asyncio.sleep(1)
if name == "B":
raise ValueError("B 出错了")
return f"{name} 成功"
except Exception as e:
return f"{name} 失败:{e}"
async def main():
results = await asyncio.gather(
safe_task("A"),
safe_task("B"),
safe_task("C"),
)
print(results)
asyncio.run(main())
示例4-Semaphore —— 控制并发数
import asyncio
import random
class RateLimiter:
def __init__(self, max_concurrent: int = 3):
self.semaphore = asyncio.Semaphore(max_concurrent)
async def request(self, url: str) -> str:
async with self.semaphore: # 获取信号量
print(f"⬇️ 请求:{url}(并发中)")
delay = random.uniform(0.5, 1.5)
await asyncio.sleep(delay)
return f"✅ {url} 完成"
async def main():
limiter = RateLimiter(max_concurrent=3)
# 同时启动 10 个任务,但最多 3 个并发
tasks = [limiter.request(f"http://api.com/{i}") for i in range(10)]
results = await asyncio.gather(*tasks)
for r in results:
print(r)
asyncio.run(main())
示例5- 天气查询 —
# 导入异步IO核心库,用于实现并发网络请求
import asyncio
# 随机数库,模拟请求延迟、随机报错、随机温度
import random
# 时间模块,统计程序整体运行耗时
import time
# 数据类装饰器,快速定义存储天气信息的数据模型
from dataclasses import dataclass
# 类型注解:列表、可选类型(可为None)
from typing import List, Optional
# 天气数据数据类:统一存储每个城市的查询结果
@dataclass
class WeatherData:
# 城市名称
city: str
# 城市温度,请求失败时填0
temp: int
# 错误信息,查询正常则为None,可选字段默认None
error: Optional[str] = None
# 异步天气请求API封装类
class AsyncWeatherAPI:
def __init__(self, max_concurrent: int = 3, timeout: float = 2.0):
"""
构造函数初始化请求限制与超时配置
:param max_concurrent: 最大并发请求数,信号量控制限流
:param timeout: 单次请求基础超时阈值
"""
# 异步信号量:控制最大并发,防止同时发起过多请求触发接口限流
self.semaphore = asyncio.Semaphore(max_concurrent)
# 基础超时时间,批量总超时会基于该值放大
self.timeout = timeout
async def fetch_one(self, city: str) -> WeatherData:
"""
获取单个城市天气(带并发限流保护)
:param city: 需要查询的城市名
:return: WeatherData 对象,包含温度或错误信息
"""
# async with 自动获取/释放信号量,保证同一时间并发不超过上限
async with self.semaphore:
try:
# 模拟网络请求延迟:0.3~1.5秒随机耗时
delay = random.uniform(0.3, 1.5)
# 异步休眠,不阻塞其他协程执行
await asyncio.sleep(delay)
# 10%概率模拟接口异常报错
if random.random() < 0.1:
raise ValueError("API 错误")
# 请求成功:返回随机15~35度的天气数据,无错误
return WeatherData(city=city, temp=random.randint(15, 35))
except Exception as e:
# 捕获所有异常,返回带错误标记的空温度数据
return WeatherData(city=city, temp=0, error=str(e))
async def fetch_batch(self, cities: list[str]) -> list[WeatherData]:
"""
批量查询多个城市天气,全局总超时控制
:param cities: 待查询城市列表
:return: 所有城市的天气结果列表
"""
try:
# asyncio.wait_for:给整批协程设置总超时时间
# asyncio.gather:并发执行所有单个城市查询协程,收集全部结果
return await asyncio.wait_for(
asyncio.gather(*[self.fetch_one(c) for c in cities]),
timeout=self.timeout * 2 # 批量总超时设为基础超时的2倍
)
except TimeoutError:
# 整批请求超时:所有城市统一标记"整体超时"错误
return [WeatherData(city=c, temp=0, error="整体超时") for c in cities]
# 程序主异步入口函数
async def main():
# 实例化天气API:最大并发5,单次基础超时2秒
api = AsyncWeatherAPI(max_concurrent=5, timeout=2.0)
# 待查询城市列表
cities = ["北京", "上海", "西安", "广州", "成都", "武汉", "南京", "杭州"]
print(f"🌤️ 开始查询 {len(cities)} 个城市...")
# 记录程序开始时间,用于计算总耗时
start = time.time()
# 批量异步查询所有城市天气
results = await api.fetch_batch(cities)
# 遍历打印每个城市的查询结果
for data in results:
if data.error:
# 存在错误信息,打印失败日志
print(f" ❌ {data.city}:{data.error}")
else:
# 查询成功,打印城市温度
print(f" ✅ {data.city}:{data.temp}°C")
# 计算并打印整体执行耗时,保留2位小数
print(f"⏱️ 耗时:{time.time() - start:.2f}秒")
# 异步程序固定启动入口,运行主协程
asyncio.run(main())
更多推荐

所有评论(0)