25
# 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()
    
4

2 回答 2

18

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

正如这篇文章所说:

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

于 2014-05-24T16:28:16.913 回答
2

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

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

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

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

于 2013-02-26T00:36:10.750 回答