請勿使用BackgroundTask
解決方案運行後臺任務,因爲它將運行在線程中,並且由於GIL,cherrypy將無法應答新請求。使用隊列解決方案在不同的進程中運行後臺任務,如Celery或RQ。
我打算詳細介紹一個使用RQ的例子。 RQ使用Redis作爲消息代理,因此首先需要安裝並啓動Redis。
然後創建一個模塊(mytask
在我的例子)與長時間運行的後臺方法:
import time
def long_running_task(value):
time.sleep(15)
return len(value)
開始一個(或不止一個,如果你想運行並行任務)RQ工人,這一點很重要該運行你的員工蟒蛇訪問您mytask
模塊(運行工人之前導出PYTHONPATH如果你的模塊是不是已經在路徑):
# rq worker
在上面,你有一個非常簡單的Web應用程序的CherryPy展示瞭如何使用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,最有可能的WebSockets更新Web瀏覽器的工作狀態。
很好的回答,謝謝!我最終用一種類似的架構對它進行了黑客攻擊,但幾乎沒有你所做的那麼整齊。我還沒有聽說過芹菜或RQ,但我會考慮將來使用它們。 – Mourndark