Python Asyncio多无限循环异步函数出错时周期延迟问题咨询
问题分析与解决方案
核心原因
你遇到的延迟问题,本质是get_exchange_rate()里用的requests是同步阻塞库。当触发SSLError并自动重试时,整个asyncio事件循环会被这个同步阻塞操作卡住——因为asyncio是单线程模型,一旦某个任务占用了线程,其他任务(比如每5秒执行的data_input())就只能等待,直到阻塞操作结束,自然就出现了延迟。
解决方法
1. 改用异步HTTP库(推荐)
把同步的requests换成异步HTTP库(比如aiohttp),让网络请求变成非阻塞操作,不会卡住事件循环。
示例代码:
import aiohttp import asyncio from bs4 import BeautifulSoup async def get_exchange_rate(): while True: try: async with aiohttp.ClientSession() as session: async with session.get("目标URL") as resp: resp.raise_for_status() html = await resp.text() soup = BeautifulSoup(html, "html.parser") # 处理汇率解析逻辑 except aiohttp.ClientError as e: print(f"请求出错: {e}") await asyncio.sleep(30) async def data_input(): while True: # 数据保存逻辑 print("执行数据保存") await asyncio.sleep(5) async def main(): await asyncio.gather( get_exchange_rate(), data_input(), return_exceptions=True ) if __name__ == "__main__": asyncio.run(main())
2. 给同步请求套线程池(兼容现有代码)
如果不想替换requests,可以用asyncio.to_thread()(Python 3.9+)或者loop.run_in_executor()把同步的requests操作放到线程池执行,避免阻塞事件循环。
示例代码:
import requests import asyncio from bs4 import BeautifulSoup async def get_exchange_rate(): while True: try: # 把同步请求放到线程池执行 response = await asyncio.to_thread(requests.get, "目标URL") response.raise_for_status() soup = BeautifulSoup(response.text, "html.parser") # 处理汇率解析逻辑 except requests.exceptions.SSLError as e: print(f"SSL错误: {e}") await asyncio.sleep(30) async def data_input(): while True: print("执行数据保存") await asyncio.sleep(5) async def main(): await asyncio.gather( get_exchange_rate(), data_input(), return_exceptions=True ) if __name__ == "__main__": asyncio.run(main())
3. 优化错误重试逻辑
不管用哪种方式,都要在get_exchange_rate()里明确捕获SSLError,避免无限制的自动重试(requests默认重试可能耗时很久),同时控制重试的间隔,减少对事件循环的影响。
比如在捕获错误后,直接进入下一个30秒周期:
async def get_exchange_rate(): while True: try: # 请求逻辑 except requests.exceptions.SSLError as e: print(f"SSL错误,跳过本次请求: {e}") # 不管成功失败,都等待30秒再执行下一次 await asyncio.sleep(30)
内容的提问来源于stack exchange,提问作者윤태일
相关产品推荐
相关产品推荐

