You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免Bokeh Server中不同应用实例出现相同图表?

解决Bokeh Server多应用图表重复的问题

我之前也碰到过一模一样的问题——Bokeh Server上部署的多个应用总是显示相同的图表,排查下来核心原因就是多个应用之间意外共享了同一个Bokeh组件实例(比如Figure、ColumnDataSource这些),导致状态串了。下面是几个能彻底解决这个问题的关键方案:

1. 确保每个应用创建独立的Bokeh组件

绝对不要在应用函数的外部定义图表、数据源这些对象,一定要把它们放在应用的回调函数内部,让每个应用实例都生成全新的组件副本。

举个错误示范(会导致重复):

# 错误:全局共享图表对象,所有应用都会用这个p
p = figure(title="Shared Plot")
p.line([1,2,3], [4,5,6])

def bad_app(doc):
    doc.add_root(p)

正确的写法(每个应用独立生成组件):

# 正确:每次调用应用函数都创建新的图表
def good_app(doc):
    p = figure(title="Unique Plot")
    p.line([1,2,3], [4,5,6])
    doc.add_root(p)

2. 严格隔离应用的状态数据

如果你的应用依赖外部数据或者可变状态(比如动态更新的数据源),一定要给每个应用分配独立的状态副本,不能让多个应用共享同一个可变对象。比如:

def app_with_unique_data(doc):
    # 每个应用实例都创建自己的数据源
    source = ColumnDataSource(data={'x': [1,2,3], 'y': [4,5,6]})
    p = figure()
    p.circle(x='x', y='y', source=source)
    doc.add_root(p)

这样即使多个用户访问同一个应用,或者多个应用同时运行,它们的数据源也不会互相干扰。

3. 优化Bokeh Server的启动逻辑

看你的代码,用multiprocessing启动Server是没问题的,但要注意几个细节:

  • 不要在主进程中提前创建Bokeh应用的组件,最好把组件创建逻辑放在子进程执行的代码里,避免父进程的状态被继承。
  • 可以考虑去掉p.join(),否则主进程会被阻塞,无法处理其他任务(如果不需要等待子进程结束的话)。

修改后的示例代码:

import multiprocessing
from bokeh.server.server import Server

def setup_bokeh_server(data):
    ''' Sets up Bokeh Application instances on server. '''
    def run_server(url_func_map):
        # 在子进程内部初始化Server,避免状态共享
        server = Server(url_func_map, allow_websocket_origin=['localhost:8888', 'localhost:5006'])
        server.start()
        server.io_loop.start()
    
    url_func_map = {}
    for name, app_func in data['bokeh_apps'].items():
        # 确保每个app_func都是独立无状态的,内部创建自己的组件
        url_func_map['/'+name] = app_func
    
    p = multiprocessing.Process(target=run_server, args=(url_func_map,))
    p.start()
    # 若主进程不需要阻塞,注释掉下面这行
    # p.join()

4. 用Bokeh Application Handler封装应用

更规范的做法是用FunctionHandler和Application类来封装每个应用,确保每个应用都是完全独立的实例:

from bokeh.application import Application
from bokeh.application.handlers import FunctionHandler
from bokeh.plotting import figure

def create_app_one():
    def app(doc):
        p = figure(title="App 1 Unique Plot")
        p.circle([1,2,3], [4,5,6])
        doc.add_root(p)
    return Application(FunctionHandler(app))

def create_app_two():
    def app(doc):
        p = figure(title="App 2 Unique Plot")
        p.line([1,2,3], [6,5,4])
        doc.add_root(p)
    return Application(FunctionHandler(app))

# 构建应用映射时使用独立的Application实例
data = {
    'bokeh_apps': {
        'app1': create_app_one(),
        'app2': create_app_two()
    }
}

这样每个应用都有自己的Handler和文档上下文,完全不会出现图表重复的问题。

核心总结下来就是:状态隔离是关键——每个Bokeh应用必须拥有自己独立的文档、图表、数据源等组件,绝对不能在多个应用之间复用这些对象。

内容的提问来源于stack exchange,提问作者Martin Sundequist

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:47:37