如何尽快 return 来自 CherryPy BackgroundTask 运行 的数据
How to return data from a CherryPy BackgroundTask running as fast as possible
我正在构建一个 Web 服务,用于使用 CherryPy 对数据进行迭代批处理。理想的工作流程如下:
- 用户POST数据交给服务处理
- 当处理作业空闲时,它收集排队的数据并开始另一个迭代
- 在处理作业时,用户POST将更多数据放入队列以供下一次迭代
- 当前迭代完成后,返回结果,以便用户可以使用相同的 API。
- 作业再次从下一批排队数据开始。
这里的关键考虑因素是处理应该 运行 尽可能快,每次迭代在前一个迭代完成后立即开始,无论队列中的数据量如何。每次迭代需要多长时间没有上限,所以我无法为其创建固定的时间表 运行。
有几个使用 BackgroundTask
(like this one) 的例子,但我还没有找到一个处理返回数据的例子,或者一个处理任务的例子 运行ning尽可能快,而不是固定的时间表。
我并不拘泥于 BackgroundTask
解决方案,所以如果有人可以提供替代方案,我将非常高兴。不过感觉框架内有解决办法。
不要运行后台任务使用BackgroundTask
解决方案,因为它会运行在一个线程中,并且由于GIL, cherrypy won't be able to answer new requests. Use a queue solution that runs your background tasks in a different process, like Celery or RQ。
我将详细开发一个使用 RQ 的示例。 RQ使用Redis作为消息代理,所以首先需要安装并启动Redis。
然后用长时间运行ning后台方法创建一个模块(在我的例子中是mytask
):
import time
def long_running_task(value):
time.sleep(15)
return len(value)
启动一个(或者多个,如果你想 运行 任务并行)RQ 工作人员,重要的是 python 是 运行 你的工作人员可以访问您的 mytask
模块(如果您的模块不在路径中,则在 运行 工作之前导出 PYTHONPATH):
# rq worker
上面有一个非常简单的 cherrypy webapp,展示了如何使用 RQ 队列:
import cherrypy
from redis import Redis
from rq import Queue
from mytask import long_running_task
class BackgroundTasksWeb(object):
def __init__(self):
self.queue = Queue(connection=Redis())
self.jobs = []
@cherrypy.expose
def index(self):
html = ['<html>', '<body>']
html += ['<form action="job">', '<input name="q" type="text" />', '<input type="submit" />', "</form>"]
html += ['<iframe width="100%" src="/results" />']
html += ['</body>', '</html>']
return '\n'.join(html)
@cherrypy.expose
def results(self):
html = ['<html>', '<head>', '<meta http-equiv="refresh" content="2" >', '</head>', '<body>']
html += ['<ul>']
html += ['<li>job:{} status:{} result:{} input:{}</li>'.format(j.get_id(), j.get_status(), j.result, j.args[0]) for j in self.jobs]
html += ['</ul>']
html += ['</body>', '</html>']
return '\n'.join(html)
@cherrypy.expose
def job(self, q):
job = self.queue.enqueue(long_running_task, q)
self.jobs.append(job)
raise cherrypy.HTTPRedirect("/")
cherrypy.quickstart(BackgroundTasksWeb())
在生产网络应用程序中,我会使用 jinja2 模板引擎来生成 html,并且很可能使用 websockets 来更新网络浏览器中的作业状态。
我正在构建一个 Web 服务,用于使用 CherryPy 对数据进行迭代批处理。理想的工作流程如下:
- 用户POST数据交给服务处理
- 当处理作业空闲时,它收集排队的数据并开始另一个迭代
- 在处理作业时,用户POST将更多数据放入队列以供下一次迭代
- 当前迭代完成后,返回结果,以便用户可以使用相同的 API。
- 作业再次从下一批排队数据开始。
这里的关键考虑因素是处理应该 运行 尽可能快,每次迭代在前一个迭代完成后立即开始,无论队列中的数据量如何。每次迭代需要多长时间没有上限,所以我无法为其创建固定的时间表 运行。
有几个使用 BackgroundTask
(like this one) 的例子,但我还没有找到一个处理返回数据的例子,或者一个处理任务的例子 运行ning尽可能快,而不是固定的时间表。
我并不拘泥于 BackgroundTask
解决方案,所以如果有人可以提供替代方案,我将非常高兴。不过感觉框架内有解决办法。
不要运行后台任务使用BackgroundTask
解决方案,因为它会运行在一个线程中,并且由于GIL, cherrypy won't be able to answer new requests. Use a queue solution that runs your background tasks in a different process, like Celery or RQ。
我将详细开发一个使用 RQ 的示例。 RQ使用Redis作为消息代理,所以首先需要安装并启动Redis。
然后用长时间运行ning后台方法创建一个模块(在我的例子中是mytask
):
import time
def long_running_task(value):
time.sleep(15)
return len(value)
启动一个(或者多个,如果你想 运行 任务并行)RQ 工作人员,重要的是 python 是 运行 你的工作人员可以访问您的 mytask
模块(如果您的模块不在路径中,则在 运行 工作之前导出 PYTHONPATH):
# rq worker
上面有一个非常简单的 cherrypy webapp,展示了如何使用 RQ 队列:
import cherrypy
from redis import Redis
from rq import Queue
from mytask import long_running_task
class BackgroundTasksWeb(object):
def __init__(self):
self.queue = Queue(connection=Redis())
self.jobs = []
@cherrypy.expose
def index(self):
html = ['<html>', '<body>']
html += ['<form action="job">', '<input name="q" type="text" />', '<input type="submit" />', "</form>"]
html += ['<iframe width="100%" src="/results" />']
html += ['</body>', '</html>']
return '\n'.join(html)
@cherrypy.expose
def results(self):
html = ['<html>', '<head>', '<meta http-equiv="refresh" content="2" >', '</head>', '<body>']
html += ['<ul>']
html += ['<li>job:{} status:{} result:{} input:{}</li>'.format(j.get_id(), j.get_status(), j.result, j.args[0]) for j in self.jobs]
html += ['</ul>']
html += ['</body>', '</html>']
return '\n'.join(html)
@cherrypy.expose
def job(self, q):
job = self.queue.enqueue(long_running_task, q)
self.jobs.append(job)
raise cherrypy.HTTPRedirect("/")
cherrypy.quickstart(BackgroundTasksWeb())
在生产网络应用程序中,我会使用 jinja2 模板引擎来生成 html,并且很可能使用 websockets 来更新网络浏览器中的作业状态。