使用aiohttp每0.1秒发送API请求并满足条件时提前退出的实现问题
问题根因
你当前的代码是串行执行每个请求的完整流程:for循环中每一轮都要依次等待asyncio.sleep(0.1)、请求发送、响应返回、结果校验全部完成,才会进入下一轮。await会阻塞当前协程的执行,所以最终的请求间隔等于「0.1s + 单次请求往返耗时」,自然达不到预期的10次/秒速率。
另外你当前的代码已经在共享ClientSession了,还可以通过优化连接池配置进一步提升性能。
优化方案
核心思路是分离请求调度和响应处理:用一个独立协程严格按0.1s间隔发送请求,每个请求的响应处理放到后台异步运行,一旦有请求满足终止条件,就触发全局停止信号,终止所有未完成的任务。
修改后的代码如下:
import time import datetime import aiohttp import asyncio url = 'http://www.randomnumberapi.com/api/v1.0/random' # 终止信号 stop_event = asyncio.Event() # 存储所有未完成的请求任务 pending_tasks = set() async def handle_response(response_future, req_id): """异步处理请求响应""" try: response = await response_future answer_list = await response.json() ans = answer_list[0] print(f"请求{req_id}返回结果:{ans}") # 替换成你自己的校验逻辑 if req_id == 25: print('early exit condition met') stop_event.set() except Exception as e: print(f"请求{req_id}出错:{str(e)}") async def main(): # 优化session配置,开启连接池复用,适配同端点高频请求 connector = aiohttp.TCPConnector( limit=100, # 连接池大小,根据并发量调整 ttl_dns_cache=300, enable_cleanup_closed=True ) async with aiohttp.ClientSession(connector=connector) as session: req_id = 0 # 最多发100次请求,或者收到停止信号就终止 while req_id < 100 and not stop_event.is_set(): start_schedule = time.time() print(f'{req_id}: 发送时间 {datetime.datetime.now()}') # 发起请求不等待响应,直接丢给后台处理 resp_future = session.get(url) task = asyncio.create_task(handle_response(resp_future, req_id)) pending_tasks.add(task) task.add_done_callback(pending_tasks.discard) req_id += 1 # 精准控间隔,补偿调度耗时,避免累积误差 cost = time.time() - start_schedule sleep_time = max(0, 0.1 - cost) await asyncio.sleep(sleep_time) # 等待所有未完成的任务结束,不需要保留结果的话也可以直接取消 await asyncio.gather(*pending_tasks, return_exceptions=True) return req_id - 1 if __name__ == "__main__": loop = asyncio.get_event_loop() ans = loop.run_until_complete(main()) print(ans)
优化说明
- 发送请求的协程仅负责按间隔发起请求,不会等待响应返回,所以请求发送间隔严格控制在0.1s,符合10次/秒的速率限制要求
- 所有请求的IO等待是并行处理的,充分发挥异步的性能优势
- 复用ClientSession的同时优化了TCP连接池配置,同一个端点的请求会复用TCP连接,减少三次握手等额外开销,进一步降低请求耗时
- 用事件对象实现提前终止逻辑,一旦有请求满足条件就能立即停止发送新请求
内容的提问来源于stack exchange,提问作者user5364303
相关产品推荐
相关产品推荐

