如何按指定周期无等待请求RestAPI?Thread与asyncio选型及实现
最优方案选择与实现
方案对比与结论
你的场景是固定间隔发送请求,不需要极高并发量,线程(Thread)方案是最优解——原因很简单:改动成本极低,不用重构原有基于requests的代码,学习和实现成本都远低于asyncio。asyncio更适合高并发场景(比如同时发起成百上千个请求),但对你当前的需求来说有点大材小用。
如果未来需要扩展到高并发场景,再切换到asyncio也不迟,现在先用线程方案快速解决问题。
线程方案实现(修改后的代码)
核心改动点:
- 用
threading.Thread把请求逻辑放到后台线程执行,主循环不用等待响应 - 加线程锁(
threading.Lock)保证文件写入的线程安全,避免多线程同时写文件导致数据乱序或损坏
import time import requests import threading # 创建线程锁,保证文件写入安全 file_lock = threading.Lock() url = 'http://127.0.0.1:8000/data' def retrieve_data(): try: response = requests.get(url) # 写入文件时加锁 with file_lock: with open('save_data.csv', 'a') as file: # 改用追加模式,避免每次覆盖 file.write(response.text + '\n') return True except Exception as e: # 打印错误信息方便排查 print(f"请求出错: {str(e)}") return False interval = 0.5 while True: # 启动后台线程执行请求,主循环不用等待 threading.Thread(target=retrieve_data, daemon=True).start() # 主循环按间隔休眠 time.sleep(interval)
关键说明:
- 把文件打开方式从
w(覆盖)改成a(追加),避免每次请求清空文件 - 用
daemon=True创建守护线程,主程序退出时线程会自动终止 - 加
file_lock确保同一时间只有一个线程写文件,防止数据混乱 - 捕获异常时打印具体错误,方便排查问题
备选:asyncio方案实现
如果之后需要高并发,推荐用aiohttp替代requests(requests是同步库,无法直接在asyncio中使用),代码如下:
import asyncio import aiohttp url = 'http://127.0.0.1:8000/data' file_lock = asyncio.Lock() # 异步锁 async def retrieve_data(session): try: async with session.get(url) as response: response_text = await response.text() async with file_lock: with open('save_data.csv', 'a') as file: file.write(response_text + '\n') return True except Exception as e: print(f"请求出错: {str(e)}") return False async def main(): interval = 0.5 async with aiohttp.ClientSession() as session: while True: # 并发执行请求,主协程继续休眠 asyncio.create_task(retrieve_data(session)) await asyncio.sleep(interval) if __name__ == "__main__": asyncio.run(main())
关键说明:
- 必须用
aiohttp作为异步HTTP客户端,不能用requests - 用
asyncio.create_task创建异步任务,无需等待任务完成 - 异步场景下用
asyncio.Lock保证文件写入安全 - 用
ClientSession复用连接,提升请求性能
内容的提问来源于stack exchange,提问作者ali
相关产品推荐
相关产品推荐

