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 接口参数传递时,编译器是不是应该提示/警告?