同步:一条队列排队打饭一个一个来
异步:开设多条队列,分批排队打饭
代码示例使用主流的httpx
同步:
import httpx
import time
def fetch_sync(client, url):
response = client.get(url)
return response.status_code
def main():
url = "https://httpbin.org/delay/1" # 模拟延迟 1 秒
times = 5
start = time.time()
with httpx.Client() as client:
for i in range(times):
print(f"正在同步请求 {i+1}/{times}...")
try:
status = fetch_sync(client, url)
print(f"请求 {i+1} 完成,状态码:{status}")
except Exception as e:
print(f"请求 {i+1} 失败:{e}")
end = time.time()
print(f"\n✅ 同步总耗时:{end - start:.2f} 秒")
print(f"📊 平均每个请求耗时:{(end - start) / times:.2f} 秒")
if __name__ == "__main__":
main()
运行结果: 正在同步请求 1/5... 请求 1 完成,状态码:200 正在同步请求 2/5... 请求 2 完成,状态码:200 正在同步请求 3/5... 请求 3 完成,状态码:200 正在同步请求 4/5... 请求 4 完成,状态码:200 正在同步请求 5/5... 请求 5 完成,状态码:200
✅ 同步总耗时:13.32 秒 📊 平均每个请求耗时:2.66 秒
异步:
import httpx
import asyncio
import time
async def fetch_async(client, url, sem):
# sem 是信号量,用于控制并发数量,防止瞬间请求太多被封 IP
async with sem:
try:
# httpx 的异步请求方式
response = await client.get(url, timeout=30.0)
status = response.status_code
print(f"请求完成,状态码:{status}")
return status
except httpx.TimeoutException as e:
print(f"请求超时:{e}")
return None
except httpx.RequestError as e:
print(f"请求失败:{e}")
return None
async def main():
url = "https://httpbin.org/delay/1"
times = 5
# 创建信号量,限制最大并发数为 5
sem = asyncio.Semaphore(5)
start = time.time()
# limits 参数可以控制连接池大小
limits = httpx.Limits(max_keepalive_connections=5, max_connections=10)
async with httpx.AsyncClient(limits=limits) as client:
# 创建任务列表
tasks = []
for i in range(times):
print(f"正在发起异步请求 {i+1}/{times}...")
task = asyncio.create_task(fetch_async(client, url, sem))
tasks.append(task)
# 等待所有任务完成
await asyncio.gather(*tasks)
end = time.time()
print(f"\n✅ 异步总耗时:{end - start:.2f} 秒")
print(f"📊 平均每个请求耗时:{(end - start) / times:.2f} 秒")
if __name__ == "__main__":
asyncio.run(main())
运行结果 正在发起异步请求 1/5... 正在发起异步请求 2/5... 正在发起异步请求 3/5... 正在发起异步请求 4/5... 正在发起异步请求 5/5... 请求完成,状态码:200 请求完成,状态码:200 请求完成,状态码:200 请求完成,状态码:200 请求完成,状态码:200
✅ 异步总耗时:6.33 秒 📊 平均每个请求耗时:1.27 秒
得出结论:
异步请求效率高,完成耗时短