如何在Python中并行执行两个含底层请求的函数(无需异步重构)
如何在Python中并行执行两个含底层请求的函数(无需异步重构)
你的思路是对的——用threading模块来并行执行两个IO密集型的请求函数,完全不需要重构为异步代码,因为IO密集型任务在Python线程中能有效利用等待时间(GIL会在网络IO等待时释放,让其他线程运行)。不过你的代码存在一些冗余和可以简化的地方,下面我来逐一分析并给出优化方案:
一、你的原代码核心逻辑是可行的,但存在冗余
你通过threading.Thread启动两个线程执行请求函数,用队列传递结果,最后join等待线程完成——这部分确实能实现并行执行。但后续的while循环轮询队列是完全多余的:
thread.join()会阻塞主线程,直到对应的子线程完全终止- 子线程的
worker函数在执行完请求后,已经把结果put进队列了,线程终止意味着put操作已经完成,队列里一定有结果 - 因此你不需要轮询队列是否为空,直接调用
queue.get()就能立即拿到结果
另外,原代码的while循环还存在bug:
- 把第二个队列的结果错误赋值给
first变量(应该是second = queue_second.get(...)) - 错误地通过
queue.empty()判断任务是否完成,这在join之后完全没必要(线程已经结束,队列不可能为空)
二、简化后的代码
下面是优化后的版本,保留你的核心并行逻辑,去掉冗余代码并修复潜在问题:
1. 基础简化版
import threading import queue def worker(function, queue_prepared, *args): # 执行请求函数并将结果放入队列 result = function(*args) queue_prepared.put(result) def launch_threads(param1, param2): queue_first = queue.Queue() queue_second = queue.Queue() # 启动两个线程,分别执行不同的请求函数 thread_first = threading.Thread( target=worker, args=(request1, queue_first, param1, param2) ) thread_second = threading.Thread( target=worker, args=(request2, queue_second, param1) ) thread_first.start() thread_second.start() # 等待两个线程都执行完毕 thread_first.join() thread_second.join() # 线程结束后,队列中肯定有结果,直接取出返回 return queue_first.get(), queue_second.get() # 调用并获取结果 result1, result2 = launch_threads(param1, param2)
2. 增加异常处理的健壮版本
如果请求函数可能抛出异常(比如网络错误),可以在worker中捕获异常并传递给主线程,避免子线程悄悄出错:
import threading import queue def worker(function, queue_prepared, *args): try: result = function(*args) # 用元组标记成功状态和结果 queue_prepared.put((True, result)) except Exception as e: # 传递异常信息给主线程 queue_prepared.put((False, e)) def launch_threads(param1, param2): queue_first = queue.Queue() queue_second = queue.Queue() thread_first = threading.Thread( target=worker, args=(request1, queue_first, param1, param2) ) thread_second = threading.Thread( target=worker, args=(request2, queue_second, param1) ) thread_first.start() thread_second.start() thread_first.join() thread_second.join() # 处理结果和异常 success1, res1 = queue_first.get() success2, res2 = queue_second.get() if not success1: raise res1 # 抛出子线程的异常 if not success2: raise res2 return res1, res2 # 调用时可以捕获异常 try: result1, result2 = launch_threads(param1, param2) except Exception as e: print(f"请求出错: {e}")
三、关于Python线程与IO密集型任务的说明
因为你的任务是发送HTTP请求(IO密集型),Python的threading模块完全能实现有效并行:
- Python的GIL(全局解释器锁)在遇到IO等待(比如等待网络响应)时会自动释放,让其他线程获得执行权
- 这意味着两个请求会同时发起,不需要等待第一个请求完成再执行第二个,能有效节省总耗时
备注:内容来源于stack exchange,提问作者Carabes
相关产品推荐
相关产品推荐

