Django - 如何设置异步长时间后台数据处理任务?

4
新手关于Django应用程序设计的问题:
我正在为我的网站构建报告引擎。我有大量数据(随着时间的推移越来越多),并且必须应用某些算法。计算对资源消耗很大,如果由用户请求执行这些计算是愚蠢的。因此,我考虑将它们放入后台进程中,该进程将被连续执行,并不时返回结果,这些结果可以通过Django视图例程提供给按需生成HTML输出。
我的问题是 - 建立这种系统的正确设计方法是什么?有任何想法吗?

1
你有没有研究过 Celery?它可以用来调度任务! - Thomas Orozco
3个回答

3
Celery是您最好的选择之一。我们已经成功地使用它了。它有一个强大的调度机制 - 您可以将任务安排为定时作业,也可以在用户(例如)请求时在后台触发任务。
它还提供了查询此类后台任务状态的方法,并具有许多流程控制功能。它允许非常轻松地分配工作 - 即您的Celery后台任务可以在单独的机器上运行(这对于Heroku Web/Workers拆分非常有用,其中Web进程每个请求限制为最多30秒)。它提供各种队列后端(它可以使用数据库、rabbitMQ或其他许多排队机制)。使用最简单的设置,它可以使用您的Django站点已经用于该目的的相同数据库(这使得设置变得容易)。
如果您正在使用自动化测试,它还具有帮助测试的功能 - 它可以设置为“急切”模式,在该模式下不会在后台执行后台任务 - 从而提供可预测的逻辑测试。
更多信息请参见:http://docs.celeryproject.org:8000/en/latest/django/

0

你是指将结果返回到数据库中,还是想直接从独立运行的代码中创建django视图?

如果你有大量数据,我喜欢使用Python的multiprocessing。你可以创建一个生成器,用不同的任务填充JoinableQueue和一组消费不同任务的工作进程。这样,你应该能够最大化系统资源利用率。

多处理模块还允许你在网络上执行多个任务(例如multiprocessing.Manager())。考虑到这一点,如果你需要第二台机器及时处理数据,你应该很容易扩展事物。

示例:

此示例显示如何生成多个进程。生成器函数应查询数据库以获取需要进行重负载处理的所有新条目。消费者从队列中取出各个项并进行实际计算。

import time 

from multiprocessing.queues import JoinableQueue
from multiprocessing import Process

QUEUE = JoinableQueue(-1)

def generator():
    """ Puts items in the queue. For example query database for all new, 
    unprocessed entries that need some serious math done.."""
    while True: 
        QUEUE.put("Item")
        time.sleep(0.1)


def consumer(consumer_id):
    """ Consumes items from the queue... Do your calculations here... """
    while True: 
        item = QUEUE.get()
        print "Process %s has done: %s" % (consumer_id, item)
        QUEUE.task_done()


p = Process(target=generator)
p.start()

for x in range(0, 2): 
    w = Process(target=consumer, args=(x,))
    w.start()

p.join()
w.join()

"您的意思是将结果返回到数据库中,还是想直接从独立运行的代码创建Django视图?这样无缝集成会更好。" - Gill Bates
既然你说需要处理的数据量很大,我建议你将数据保存到数据库中,并从Django查询数据库。这样,如果你使用多进程,数据就不需要创建额外的通信方式,而且数据也会被持久化。你可以只使用Django的部分功能来让其他代码部分访问数据库,例如在https://dev59.com/bXNA5IYBdhLWcg3wfeAm和https://dev59.com/tnVC5IYBdhLWcg3wbQXA中所讨论的方法。 - chkorn
1
我的困惑在于如何在Django中调用后台进程,考虑到它必须与请求无关 - 这个进程如何在服务器启动时(或按计划)启动,并持续执行? - Gill Bates
啊!现在我明白了。对于造成的困惑,我很抱歉。我建议你在数据库中设置一个标志,表示“需要完成工作”。然后,后台任务只需查询您的数据库以获取打开任务列表即可。我添加了一个消费者/生成器示例,应该可以稍微演示一下原理。这个过程可以手动启动或作为服务/守护进程启动。通过无限循环(例如 while True:)可以使其持续运行。只要确保有某种停止条件,以便您可以优雅地终止 :) - chkorn
这个过程能否放在Django运行时中,还是这是一个不好的决定?顺便说一句,谢谢你的示例! - Gill Bates
这样你就可以访问你的方法/函数等?是的,但你不一定非要这么做。如何使这些东西工作应该在上面链接的问题中有所描述。你不能将此代码作为视图或从视图中调用。我的建议需要一个独立的进程。抱歉。 - chkorn

0
为什么你不写一个URL或Python脚本,每次运行时触发需要完成的计算,然后通过服务器上的cronjob获取该URL或运行该脚本?根据你的问题,似乎你不需要更多的东西。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接