这似乎不是bokeh本身的问题,而是运行Flask应用程序的服务器中的线程和阻塞问题。
除了bokeh,它完全可以重现…
import requests
from flask import Flask, jsonify, request
import pandas
import pdb
flask_app = Flask(__name__)
# Populate some model maintained by the flask application
modelDf = pandas.DataFrame()
nData = 100
modelDf[ 'c1_x' ] = range(nData)
modelDf[ 'c1_y' ] = [ x*x for x in range(nData) ]
modelDf[ 'c2_x' ] = range(nData)
modelDf[ 'c2_y' ] = [ 2*x for x in range(nData) ]
@flask_app.route('/', methods=['GET'] )
def index():
res = "<table>"
res += "<tr><td><a href=\"http://localhost:8080/sendModelData/c1\">SEND C1</a></td></tr>"
res += "<tr><td><a href=\"http://localhost:8080/sendModelData/c2\">SEND C2</a></td></tr>"
res += "<tr><td><a href=\"http://localhost:8080/RequestsOverFlaskNoProxy?colName=c1\">REQUEST OVER FLASK NO PROXY C1</a></td></tr>"
res += "<tr><td><a href=\"http://localhost:8080/RequestsOverFlaskNoProxy?colName=c2\">REQUEST OVER FLASK NO PROXY C2</a></td></tr>"
res += "<tr><td><a href=\"http://localhost:8080/RequestsOverFlask?colName=c1\">REQUEST OVER FLASK C1</a></td></tr>"
res += "<tr><td><a href=\"http://localhost:8080/RequestsOverFlask?colName=c2\">REQUEST OVER FLASK C2</a></td></tr>"
res += "</table>"
return res
@flask_app.route('/RequestsOverFlaskNoProxy')
def requestsOverFlaskNoProxy() :
print("RequestsOverFlaskNoProxy")
# get column name from query string
colName = request.args.get('colName')
# get model data from Flask
url = "http://localhost:8080/sendModelData/%s" % colName
print("Get data from %s" % url )
session = requests.Session()
session.trust_env = False
res = session.get( url , timeout=5000 , verify=False )
print( "CODE %s" % res.status_code )
print( "ENCODING %s" % res.encoding )
print( "TEXT %s" % res.text )
data = res.json()
return data
@flask_app.route('/RequestsOverFlask')
def requestsOverFlask() :
# get column name from query string
colName = request.args.get('colName')
# get model data from Flask
url = "http://localhost:8080/sendModelData/%s" % colName
res = requests.get( url , timeout=None , verify=False )
print( "CODE %s" % res.status_code )
print( "ENCODING %s" % res.encoding )
print( "TEXT %s" % res.text )
data = res.json()
return data
@flask_app.route('/sendModelData/<colName>' , methods=['GET'] )
def sendModelData( colName ) :
x = modelDf[ colName + "_x" ].tolist()
y = modelDf[ colName + "_y" ].tolist()
return jsonify( x=x , y=y )
if __name__ == '__main__':
print('opening Flask app on http://localhost:8080/')
# THIS DOES NOT WORK
#flask_app.run( host='0.0.0.0' , port=8080 , debug=True )
# THIS WORKS
flask_app.run( host='0.0.0.0' , port=8080 , debug=True , threaded=True )
从屏幕截图中可以看出,直接从sendModelData
JSon提供数据会适当地呈现JSon,但是通过requests.get
Python控制台中报告的503代码,通过该方法获取时会产生异常。
如果我尝试尝试消除通过环境变量启用的代理的影响,但这种方法将永远无法完成,并且请求将使浏览器无限期旋转。
想到它,甚至完全没有必要以中间人的身份使用请求,而且我应该能够只获取json字符串并自行反序列化。好吧,在我的实际代码中,通过在与Flask应用程序完全不同的python模块中完成bokeh渲染,可以在此设置中起作用,因此除非我加扰应用程序的分层,否则这些功能甚至不可用。
编辑事实证明,我违反的基本原则是Flask的开发环境…
您正在通过Flask测试服务器运行WSGI应用程序,该服务器默认情况下使用单个线程来处理请求。因此,当您的一个请求线程尝试回拨到同一服务器时,它仍在忙于处理该请求。
因此,问题就变成了如何在原始bokeh示例中应用threaded = True技术?flask_embed.py示例对Tornado WSGI服务器的依赖可能无法实现,从这个问题可以看出Tornado在设计上是单线程的。鉴于上述发现,一个甚至更尖锐的问题是,如何AjaxDataSource
共同避免requests
模块所面临的这些线程问题?
有关散景和龙卷风耦合的更多背景信息…
53:05因此实际上它们不是很多,问题是关于bokeh和bokeh服务器的依赖关系。新的bokeh服务器基于龙卷风构建,这几乎是主要依赖项,因为它使用了龙卷风。除此之外,对于bokeh而言,没有太多依赖关系(运行时依赖关系)。pandas是bokeh.charts的可选依赖项。还有其他依赖项,您知道使用了numpy。但是,我认为只有六个或七个依赖项。多年来,我们一直在努力将其削减很多,但是服务器的主要依赖性是龙卷风。Bokeh数据可视化简介-第1部分- Strata Hadoop San Jose 2016