python - 如何从尽可能快运行的 CherryPy BackgroundTask 返回数据

标签 python python-2.7 cherrypy python-multithreading

我正在使用 CherryPy 构建一个用于迭代批处理数据的 Web 服务。理想的工作流程如下:

  1. 用户将数据发布到服务进行处理
  2. 当处理作业空闲时,它会收集排队的数据并开始另一次迭代
  3. 在处理作业时,用户会将更多数据发布到队列以进行下一次迭代
  4. 当前迭代完成后,结果将被传回,以便用户可以使用相同的 API 获取结果。
  5. 作业会再次开始处理下一批排队数据。

这里的关键考虑因素是,处理应该尽可能快地运行,每次迭代在前一次迭代完成后立即开始,无论队列中的数据量有多少。每次迭代可以花费的时间没有上限,因此我无法为其运行创建固定的时间表。

有一些使用 BackgroundTask ( like this one ) 的示例,但我还没有找到一个处理返回数据的示例,或者一个处理尽可能快运行的任务的示例按固定时间表进行。

我并不热衷于 BackgroundTask 解决方案,因此如果有人可以提供替代方案,我会非常高兴。不过,感觉框架内有一个解决方案。

最佳答案

不要使用 BackgroundTask 解决方案运行后台任务,因为它将在线程中运行,并且由于 GIL ,cherrypy 将无法响应新请求。使用在不同进程中运行后台任务的队列解决方案,例如 CeleryRQ

我将使用 RQ 详细开发一个示例。 RQ 使用 Redis 作为消息代理,因此首先需要安装并启动 Redis。

然后使用长时间运行的后台方法创建一个模块(在我的示例中为mytask):

import time
def long_running_task(value):
    time.sleep(15)
    return len(value)

启动一个(或者多个,如果你想并行运行任务)RQ工作线程,运行你的工作线程的Python必须能够访问你的mytask模块(在之前导出PYTHONPATH),这一点很重要如果您的模块尚未在路径中,则运行工作程序):

# rq worker

上面有一个非常简单的cherrypy web应用程序,它展示了如何使用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())

在生产 Web 应用程序中,我将使用 jinja2 模板引擎生成 html,并且最有可能使用 Websocket 来更新 Web 浏览器中的作业状态。

关于python - 如何从尽可能快运行的 CherryPy BackgroundTask 返回数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36644974/

相关文章:

python - 为什么包含 'end=' 参数的 python print 语句在 while 循环中表现不同?

python - 如何调试使 python 崩溃的 python 脚本

Python:IOError:调用中缺少参数

python - 在 Python 2.7 上使用 AttrDict 时出现奇怪的错误

python - cherrypy 两台服务器不同的端口

python - 通过网络界面显示网络摄像头(Python、CherryPy、OpenCV)

python - 未找到 cherrypy/dev/urandom(或等效项)——错误

Python subprocess.Popen - 添加 GCcflags导致 "no input files"错误

python - 升级: 'module' object has no attribute 'SSL_ST_INIT' 后pip出错

python - 如何在python和go语言之间共享变量?