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

Python 如何从运行得尽可能快的CherryPy BackgroundTask返回数据,python,python-2.7,cherrypy,python-multithreading,Python,Python 2.7,Cherrypy,Python Multithreading,我正在使用CherryPy构建一个用于迭代批处理数据的web服务。理想的工作流程如下: 用户将数据发布到服务以进行处理 当处理作业空闲时,它收集排队的数据并开始另一次迭代 当作业正在处理时,用户正在向队列中发布更多数据,以供下一次迭代 一旦当前迭代完成,结果就会传回,以便用户可以使用相同的API获得它们 作业将使用下一批排队数据再次启动 这里需要考虑的关键问题是,无论队列中的数据量有多大,每次迭代都应在前一次迭代完成后立即开始,处理应尽可能快地运行。对于每次迭代所需的时间没有上限,因此我无法为它

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

  • 用户将数据发布到服务以进行处理
  • 当处理作业空闲时,它收集排队的数据并开始另一次迭代
  • 当作业正在处理时,用户正在向队列中发布更多数据,以供下一次迭代
  • 一旦当前迭代完成,结果就会传回,以便用户可以使用相同的API获得它们
  • 作业将使用下一批排队数据再次启动
  • 这里需要考虑的关键问题是,无论队列中的数据量有多大,每次迭代都应在前一次迭代完成后立即开始,处理应尽可能快地运行。对于每次迭代所需的时间没有上限,因此我无法为它创建一个固定的运行时间表

    有几个使用
    BackgroundTask
    ()的例子,但我还没有找到一个处理返回数据的例子,或者一个处理运行速度尽可能快而不是按固定时间表运行的任务的例子


    我不喜欢
    BackgroundTask
    解决方案,所以如果有人能提供一个替代方案,我会非常高兴。不过,感觉框架中有一个解决方案。

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

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

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

    import time
    def long_running_task(value):
        time.sleep(15)
        return len(value)
    
    启动一个(如果要并行运行任务,则启动多个)RQ worker,运行worker的python必须能够访问
    mytask
    模块(如果模块不在路径中,则在运行worker之前导出python路径):

    上面有一个非常简单的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())
    
    import cherrypy
    从redis导入redis
    从rq导入队列
    从mytask导入长\u运行\u任务
    类BackgroundTasksWeb(对象):
    定义初始化(自):
    self.queue=queue(连接=Redis())
    self.jobs=[]
    @樱桃树
    def索引(自):
    html=['',]
    html+=['','','','']
    html+=['']
    html+=['',]
    返回'\n'。加入(html)
    @樱桃树
    def结果(自我):
    html=['','','','']
    html+=['
      '] html+=['
    • 作业:{}状态:{}结果:{}输入:{}
    • '.格式(self.jobs中j的j.get_id(),j.get_status(),j.result,j.args[0]) html+=['
    '] html+=['',] 返回'\n'。加入(html) @樱桃树 def作业(自我,q): job=self.queue.enqueue(长时间运行的任务,q) self.jobs.append(作业) raise cherrypy.HTTPRedirect(“/”) cherrypy.quickstart(BackgroundTasksWeb())

    在生产web应用程序中,我将使用jinja2模板引擎生成html,最有可能的是使用WebSocket在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())