Cherrypy:处理时间长的页面都有哪些解决方案
Posted
技术标签:
【中文标题】Cherrypy:处理时间长的页面都有哪些解决方案【英文标题】:Cherrypy : which solutions for pages with large processing timeCherrypy:处理时间长的页面有哪些解决方案 【发布时间】:2014-05-03 00:49:18 【问题描述】:我有一个由cherrypy 提供支持的网站。对于某些页面,我需要相当长的处理时间(数百万行数据库上的多连接 SQL 请求)。处理有时需要 20 秒或更长时间,浏览器会因为时间过长而崩溃。
我想知道这里有什么好的解决方案。
【问题讨论】:
【参考方案1】:这里的一切都取决于网站的数量。 CherryPy 是一个线程服务器,一旦每个线程都在等待数据库,新的请求将不会被处理。请求队列也有方面,但总的来说是这样。
穷人的解决方案
如果您知道您的流量很小,您可以尝试解决方法。如果需要,增加 response.timeout
(默认为 300 秒)。增加server.thread_pool
(默认为 10)。如果您在 CherryPy 应用程序前使用预留代理,如 nginx,也请增加代理超时时间。
以下解决方案将要求您重新设计您的网站。特别是让它异步,客户端代码发送一个任务,然后使用拉或推来获得它的结果。这将需要在电线的两侧进行更改。
CherryPy 后台任务
您可以在服务器端使用cherrypy.process.plugins.BackgroundTask
和一些中间存储(例如数据库中的新表)。用于拉取的 XmlHttpRequest 或用于推送到客户端的 WebSockets。 CherryPy 可以同时处理这两种情况。
请注意,由于 CherryPy 在单个 Python 进程中运行,后台任务的线程也会在其中运行。如果你做一些 SQL 结果集后处理,你会受到GIL 的影响。所以你可能想重写它以使用进程,这有点复杂。
工业解决方案
如果您的网站运行或被视为大规模运行,您最好考虑使用分布式任务队列,例如 Rq 或 Celery。它使服务器端与众不同。客户端是相同的拉或推。
示例
下面是带有 XHR 轮询的 BackgroundTags
的玩具实现。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import time
import uuid
import cherrypy
from cherrypy.process.plugins import BackgroundTask
config =
'global' :
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 8080,
'server.thread_pool' : 8,
class App:
_taskResultMap = None
def __init__(self):
self._taskResultMap =
def _target(self, task, id, arg):
time.sleep(10) # long one, right?
try:
self._taskResultMap[id] = 42 + arg
finally:
task.cancel()
@cherrypy.expose
@cherrypy.tools.json_out()
def schedule(self, arg):
id = str(uuid.uuid1())
self._taskResultMap[id] = None
task = BackgroundTask(
interval = 0, function = self._target, args = [id, int(arg)],
bus = cherrypy.engine)
task.args.insert(0, task)
task.start()
return str(id)
@cherrypy.expose
@cherrypy.tools.json_out()
def poll(self, id):
if self._taskResultMap[id] is None:
return 'id': id, 'status': 'wait', 'result': None
else:
return
'id' : id,
'status' : 'ready',
'result' : self._taskResultMap.pop(id)
@cherrypy.expose
def index(self):
return '''<!DOCTYPE html>
<html>
<head>
<title>CherryPy BackgroundTask demo</title>
<script type='text/javascript'
src='http://cdnjs.cloudflare.com/ajax/libs/qooxdoo/3.5.1/q.min.js'>
</script>
<script type='text/javascript'>
// Do not structure you real JavaScript application this way.
// This callback spaghetti is only for brevity.
function sendSchedule(arg, callback)
var xhr = q.io.xhr('/schedule?arg=' + arg);
xhr.on('loadend', function(xhr)
if(xhr.status == 200)
callback(JSON.parse(xhr.responseText))
);
xhr.send();
;
function sendPoll(id, callback)
var xhr = q.io.xhr('/poll?id=' + id);
xhr.on('loadend', function(xhr)
if(xhr.status == 200)
callback(JSON.parse(xhr.responseText))
);
xhr.send();
function start(event)
event.preventDefault();
// example argument to pass to the task
var arg = Math.round(Math.random() * 100);
sendSchedule(arg, function(id)
console.log('scheduled (', arg, ') as', id);
q.create('<li/>')
.setAttribute('id', id)
.append('<span>' + id + ': 42 + ' + arg +
' = <img src="http://sstatic.net/Img/progress-dots.gif" />' +
'</span>')
.appendTo('#result-list');
var poll = function()
console.log('polling', id);
sendPoll(id, function(response)
console.log('polled', id, '(', response, ')');
if(response.status == 'wait')
setTimeout(poll, 2500);
else if(response.status == 'ready')
q('#' + id)
.empty()
.append('<span>' + id + ': 42 + ' + arg + ' = ' +
response.result + '</span>');
);
;
setTimeout(poll, 2500);
);
q.ready(function()
q('#run').on('click', start);
);
</script>
</head>
<body>
<p>
<a href='#' id='run'>Run a long task</a>, look in browser console.
</p>
<ul id='result-list'></ul>
</body>
</html>
'''
if __name__ == '__main__':
cherrypy.quickstart(App(), '/', config)
【讨论】:
以上是关于Cherrypy:处理时间长的页面都有哪些解决方案的主要内容,如果未能解决你的问题,请参考以下文章
处理 Mozilla Firefox 中的“可见性:折叠”错误都有哪些好的解决方法?