Python中API请求无限运行时的重试处理问题求助
问题分析与解决方案
你的代码核心问题
- 线程目标参数错误:创建
Thread时直接调用run_with_timeout(inst_tokens),会导致该函数在主线程立即执行,而非子线程。正确写法应传递函数对象与参数,而非函数调用结果。 - 线程无法强制终止:Python线程没有内置强制终止机制,即便
thread.join(timeout=10)超时,子线程仍会在后台运行,后续的thread.join()会一直等待线程结束,导致程序无限挂起。
可行解决方案:用进程替代线程
进程拥有独立内存空间,可被强制终止,适合处理这类无法中断的阻塞API调用。以下是两种实现方式:
方案1:使用multiprocessing.Process
import multiprocessing import time import datetime def fetch_quotes(inst_tokens, result_queue): try: result = client.quotes(instrument_tokens=inst_tokens, quote_type="", isIndex=False) result_queue.put(result) except Exception as e: result_queue.put(e) retry_delay = 10 while True: result_queue = multiprocessing.Queue() proc = multiprocessing.Process(target=fetch_quotes, args=(inst_tokens, result_queue)) proc.start() # 等待进程结束,超时10秒 proc.join(timeout=10) if proc.is_alive(): # 超时,强制终止进程 proc.terminate() proc.join() # 确保进程彻底结束 print(f"Execution of quote API took more than 10 seconds. Retrying in {retry_delay} seconds... {datetime.datetime.now()}") time.sleep(retry_delay) continue # 获取结果 result = result_queue.get() if isinstance(result, Exception): print(f"API调用出错: {result},重试中... {datetime.datetime.now()}") time.sleep(retry_delay) continue # 成功获取数据,退出循环 break # 后续处理result
方案2:使用concurrent.futures.ProcessPoolExecutor
该方案更简洁,利用submit和result的超时参数实现控制:
from concurrent.futures import ProcessPoolExecutor, TimeoutError import time import datetime retry_delay = 10 while True: with ProcessPoolExecutor(max_workers=1) as executor: future = executor.submit(client.quotes, instrument_tokens=inst_tokens, quote_type="", isIndex=False) try: # 等待结果,超时10秒 result = future.result(timeout=10) break # 成功获取,退出循环 except TimeoutError: print(f"Execution of quote API took more than 10 seconds. Retrying in {retry_delay} seconds... {datetime.datetime.now()}") time.sleep(retry_delay) except Exception as e: print(f"API调用出错: {e},重试中... {datetime.datetime.now()}") time.sleep(retry_delay) # 后续处理result
为什么线程方案不可行?
Python线程受GIL(全局解释器锁)限制,且无法被强制终止。如果client.quotes是阻塞IO操作,子线程会一直处于阻塞状态,主线程即便判定超时,也无法中断它,最终导致程序挂起。而进程可通过terminate()强制结束,避免资源泄漏与无限等待。
内容的提问来源于stack exchange,提问作者Kuljeet Keshav
相关产品推荐
相关产品推荐

