Flask+Oracle并行查询在Bokeh脚本调用时失效问题排查
问题分析:Flask路由并发 vs Bokeh服务器调用并发的差异
这两种场景的核心差异在于请求处理的线程/进程模型以及Bokeh服务器的执行方式,我来拆解一下:
一、纯Flask路由能并行查询的原因
Flask默认使用的Werkzeug服务器(app.run()默认启动的)是多线程模式(从Flask 2.0开始默认开启)。当同时收到两个请求时:
- 每个请求会被分配到单独的线程中处理
- 每个线程可以独立从Oracle连接池获取连接(或者新建连接),数据库查询可以并行执行
- 线程之间互不阻塞,所以两个请求都能正常返回结果
二、调用Bokeh服务器时卡住的可能原因
你遇到的问题大概率出在Bokeh服务器的并发处理能力或者Flask调用Bokeh的方式上,常见的几个点:
1. Bokeh服务器默认是单线程单进程处理请求
Bokeh服务器的默认配置是单线程的,它会串行处理所有 incoming 的请求(包括WebSocket连接和HTTP请求)。如果你的两个Flask路由同时调用Bokeh服务器的接口,第二个请求必须等待第一个请求的数据库查询完成才能被处理,导致页面持续加载。
2. Flask路由在请求时才启动Bokeh服务器
如果你的Flask代码是在收到请求后才启动Bokeh服务器(比如用subprocess.run()或者直接调用bokeh serve的Python API),那第一个请求会阻塞在启动Bokeh的步骤上,第二个请求尝试再次启动时会因为端口被占用而卡住,或者等待第一个启动流程完成,最终导致两个请求都无法正常响应。
3. Bokeh代码中使用了全局Oracle连接对象
如果你的Bokeh脚本里用了全局的Oracle连接(比如在脚本顶部就创建了连接,而不是在每个请求/会话中获取),那当两个并发请求到达Bokeh服务器时,会竞争同一个连接资源——Oracle连接一般是单线程使用的,多个线程同时操作会导致阻塞甚至报错。
三、解决方案
针对这些问题,你可以按以下步骤排查修复:
- 提前独立启动Bokeh服务器:不要在Flask请求中动态启动Bokeh服务,而是在Flask启动前,用命令行(
bokeh serve --allow-websocket-origin=your-flask-domain:port your_script.py)或者后台进程启动Bokeh,Flask只负责跳转到Bokeh的URL或者做反向代理。 - 配置Bokeh服务器支持并发:启动Bokeh时加上
--num-procs N参数(N是进程数),或者--workers N(针对新版本Bokeh),让Bokeh用多进程处理请求;也可以配置--threaded开启多线程模式。 - 在Bokeh中使用Oracle连接池:在Bokeh脚本里初始化一个Oracle连接池(比如用
cx_Oracle.SessionPool),每个会话/请求从连接池获取独立的连接,用完后归还,避免线程竞争。 - 检查Flask调用Bokeh的方式:如果是用HTTP请求调用Bokeh接口,确保不要在Flask线程中做不必要的阻塞操作;如果是嵌入Bokeh组件,推荐用Bokeh的
server_document()方法,它会通过WebSocket和Bokeh服务器通信,效率更高且支持并发。
内容的提问来源于stack exchange,提问作者machump
相关产品推荐
相关产品推荐

