Python中程序某部分等待时如何执行其他操作
OpenWeatherMap API限流场景下利用等待时间处理入库任务的实现方案
核心思路是避免用同步阻塞等待浪费CPU时间,将API请求和数据入库两类IO任务解耦,在限流冷却窗口期调度执行入库任务,最大化资源利用率。
推荐方案1:生产者消费者线程模型(易维护,兼容性好)
适合中小规模请求量,代码逻辑简单易调试,不需要引入异步生态依赖。
- 初始化两个队列分别存储待请求的位置参数、待入库的天气数据
- 单独启动API请求线程,严格按照每分钟60次的速率发起请求,每满60次后进入冷却期:
- 冷却期内优先消费待入库队列的数据执行数据库写入操作
- 冷却时间到后重置请求计数,恢复API请求
- 若待入库数据量较大,可额外启动多个入库线程并行消费,API请求线程的冷却期也可参与消费,进一步提升处理速度
简化示例代码
import time import threading from queue import Queue import requests # 基础配置 OPENWEATHER_API_KEY = "替换为你的API密钥" MAX_REQUESTS_PER_MINUTE = 60 RATE_LIMIT_WINDOW_SEC = 60 # 队列初始化 pending_request_queue = Queue() pending_save_queue = Queue() # 示例:将所有待查询的城市ID写入请求队列 for city_id in [12345, 23456, 34567]: # 替换为你的实际待查询列表 pending_request_queue.put(city_id) def api_request_worker(): request_counter = 0 window_start_time = time.time() while not pending_request_queue.empty(): # 触发热限流判断 if request_counter >= MAX_REQUESTS_PER_MINUTE: elapsed_sec = time.time() - window_start_time # 未到冷却结束时间则处理入库任务 while elapsed_sec < RATE_LIMIT_WINDOW_SEC: if not pending_save_queue.empty(): weather_data = pending_save_queue.get() # 替换为你的实际数据库写入逻辑 # db_connection.insert("weather_table", weather_data) pending_save_queue.task_done() else: # 无待入库任务时短休眠避免空转消耗CPU time.sleep(0.2) elapsed_sec = time.time() - window_start_time # 冷却结束重置计数和时间窗口 request_counter = 0 window_start_time = time.time() # 发起API请求 current_city_id = pending_request_queue.get() resp = requests.get( url="https://api.openweathermap.org/data/2.5/weather", params={"id": current_city_id, "appid": OPENWEATHER_API_KEY} ) resp.raise_for_status() pending_save_queue.put(resp.json()) request_counter += 1 pending_request_queue.task_done() if __name__ == "__main__": # 启动API请求线程 threading.Thread(target=api_request_worker, daemon=True).start() # 等待所有请求和入库任务完成 pending_request_queue.join() pending_save_queue.join()
推荐方案2:异步IO模型(高性能,适合大规模请求)
如果请求量在数千以上,推荐用asyncio生态实现,单线程即可处理大量IO任务,上下文切换开销远低于多线程方案。
- 用
aiohttp发送异步API请求,用异步数据库驱动(如aiomysql、asyncpg)执行入库操作 - 用令牌桶算法控制API请求速率,令牌耗尽时调度执行待入库的异步任务
注意事项
- 建议添加请求重试逻辑,处理偶发的429限流、5xx服务错误,可通过
tenacity库快速实现重试装饰器 - 数据库写入建议批量提交,比如每攒够20~50条数据再一次性写入,可大幅降低IO开销
- 若多实例分布式部署,需将总限流配额拆分到每个实例,避免整体超过平台限流阈值
内容的提问来源于stack exchange,提问作者user17220616
相关产品推荐
相关产品推荐

