django 模型对象实例是不是应该传递给 celery?

Posted

技术标签:

【中文标题】django 模型对象实例是不是应该传递给 celery?【英文标题】:Should django model object instances be passed to celery?django 模型对象实例是否应该传递给 celery? 【发布时间】:2013-02-11 07:36:45 【问题描述】:
# models.py
from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    text_blob = models.CharField(max_length=50000)

# tasks.py
import celery
@celery.task
def my_task(person):
    # example operation: does something to person 
    # needs only a few of the attributes of person
    # and not the entire bulky record
    person.first_name = person.first_name.title()
    person.last_name = person.last_name.title()
    person.save()

在我的应用程序中,我有类似的东西:

from models import Person
from tasks import my_task
import celery
g = celery.group([my_task.s(p) for p in Person.objects.all()])
g.apply_async()
芹菜泡菜 p 送给工人吧? 如果工作人员在多台机器上运行,整个 person 对象(连同主要不需要的庞大的 text_blob)是否会通过网络传输?有没有办法避免?

如何高效、均匀地将 Person 记录分配给在多台机器上运行的工作人员?

这是一个更好的主意吗?如果 Person 有几百万条记录,它不会压倒数据库吗?

# tasks.py

import celery
from models import Person
@celery.task
def my_task(person_pk):
    # example operation that does not need text_blob
    person = Person.objects.get(pk=person_pk)
    person.first_name = person.first_name.title()
    person.last_name = person.last_name.title()
    person.save()


#In my application somewhere
from models import Person
from tasks import my_task
import celery
g = celery.group([my_task.s(p.pk) for p in Person.objects.all()])
g.apply_async()

【问题讨论】:

使用任务延迟并为此设置计时器 @catherine 在这种情况下计时器如何帮助我? 对不起那个计时器我的错误,它只是任务延迟。当人有数百万条记录时,celery 会延迟任务并通过一个一个发送来管理它 @catherine 所以,根据我从文档中了解到的情况,延迟只是 apply_async docs.celeryproject.org/en/latest/userguide/calling.html#basics 的捷径 是的,我的意思是这样的:my_task.delay(p.pk) 【参考方案1】:

我相信传递 PK 比传递整个模型对象更好更安全。由于 PK 只是一个数字,因此序列化也简单得多。最重要的是,您可以使用更安全的 sarializer(json/yaml 而不是 pickle),并且可以放心,序列化模型不会有任何问题。

正如this 文章所说:

由于 Celery 是一个分布式系统,你无法知道任务将在哪个进程中运行,甚至在哪台机器上运行。所以你不应该将 Django 模型对象作为参数传递给任务,从数据库中重新获取对象几乎总是更好,因为这可能涉及竞争条件。

【讨论】:

【参考方案2】:

是的。如果数据库中有数百万条记录,那么这可能不是最好的方法,但是由于您必须遍历所有数百万条记录,那么无论您做什么,您的数据库都会受到相当大的打击很难。

这里有一些替代品,我称之为“更好”,只是不同。

    为您的 Person 类实现一个 pre_save 信号处理程序,该处理程序执行 .title() 工作。这样,您的 first_name/last_names 将始终正确存储在数据库中,您不必再这样做了。 使用采用某种分页参数的管理命令...也许使用姓氏的第一个字母来分割人员。因此,运行./manage.py my_task a 将更新姓氏以“a”开头的所有记录。显然,您必须运行几次才能通过整个数据库 也许你可以用一些有创意的 sql 来做到这一点。我什至不打算在这里尝试,但可能值得研究。

请记住,.save() 对数据库的“打击”会比实际选择数百万条记录更难。

【讨论】:

所以 .title() 是这里的一个示例操作,我想通过它的帮助表明并非对象拥有的所有内容都被 my_task() 使用。 批量保存可以降低“命中”的强度,不是吗?但是如何高效地分批发送呢?

以上是关于django 模型对象实例是不是应该传递给 celery?的主要内容,如果未能解决你的问题,请参考以下文章

将对象实例直接作为 const 接口参数传递时,编译器是不是应该提示/警告?

Django 将多个模型传递给一个模板

Django:将变量传递给simple_tag而不是id失败

将模型属性传递给 Django 中的 URL

Django将对象列表传递给模板

Django:获取相关对象的相关对象并传递给模板