我已经构建了一个Flask应用程序,它可以计算图形中的一些路径 . 通常,这是一项非常贪婪的任务,需要花费大量时间才能完成计算 . 虽然我忙于配置算法,但我并没有真正关注服务器端的实现 . 我们已经 Build 了一个Nginx服务器,可以为整个服务器提供服务 . 这里是主要的Flask路线:
@app.route('/paths', methods=['POST'])
def paths():
form = SampleForm(request.form)
if form.validate_on_submit():
point_a = form.point_a.data
point_b = form.point_b.data
start = form.start.data.strftime('%Y%m%d')
end = form.end.data.strftime('%Y%m%d')
hops = form.hops.data
rendering_time, collections = make_collection(point_a, point_b, start, end, hops)
return render_template(
'result.html',
searching_time=rendering_time,
collections=collections)
else:
logger.warning('Bad form: {}'.format(form.errors))
return render_template('index.html', form=form)
整个计算的事情在于 make_collection
方法 . 因此,每当用户向 server.com/path
发送请求时,他都必须等待,直到该方法完成计算并返回一些内容 . 这不是一个令人愉快的解决方案,有时Nginx会超时 .
下一个版本是一个简单的想法,即将劳动工作委托给某个线程,然后只返回一个空页面给用户 . 稍后我们可以使用最新的搜索结果更新页面内容 .
@app.route('/paths', methods=['POST'])
def paths():
form = SampleForm(request.form)
if form.validate_on_submit():
point_a = form.point_a.data
point_b= form.point_b.data
start = form.start.data.strftime('%Y%m%d')
end = form.end.data.strftime('%Y%m%d')
hops = form.hops.data
finder = threading.Thread(
target=make_collection,
kwargs={
'point_a': point_a,
'point_b': point_b,
'start': start,
'end': end,
'hops': hops})
finder.start()
rendering_time, collections = 0, []
return render_template(
'result.html',
searching_time=rendering_time
collections=collections)
else:
logger.warning('Bad form: {}'.format(form.errors))
return render_template('index.html', form=form)
上面的代码工作正常,并且具有可接受的搜索时间(没有像第一个版本那样改变,就像预期的那样) . 问题是,它只在我的本地机器上工作 . 当我将其部署到Nginx时,总体性能甚至几乎都不如我所期望的那样 . 为了比较,我在30秒内在本地机器上找到的结果,即使在300秒内也无法完全找到Nginx . 该怎么办?
附:最初,设置Nginx服务器不是我工作的一部分,我不是很熟悉Nginx如何工作,但如果你需要任何信息,请问 .
1 回答
第一个代码片段看起来像是让客户端获取计算结果的简单方法 .
但是,
make_collection
是阻塞的,Nginx将让其中一名工作人员忙于它 . 由于Nginx配置的通常方式是每个CPU核心有一个工作线程,因此每次向/paths
发出HTTP请求时,都会减少一个工作线程 . 如果有多个请求/paths
,那么表现不佳并不奇怪 . 更不用说你可能拥有的WSGI服务器,例如uwsgi,gunicorn等,以及每个 Worker 的 Worker 和线程 .使用线程的解决方案看起来可能是一个很好的解决方案,但最终可能会遇到很多线程 . 注意Python中的线程,尽量避免将CPU绑定工作委托给Python中的线程,除非你真的知道自己在做什么 .
通常,您应该尝试避免这些阻塞调用,例如您创建的阻塞调用,并将它们卸载到单独的工作队列,同时保留稍后获取结果的引用 .