2013-02-26 14 views
18
# 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() 

W mojej aplikacji gdzieś mam coś takiego:Czy instancje obiektu modelu django powinny być przekazywane do selera?

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() 
  • naciowego pikle p wysłać go na prawo pracownika?
  • Jeśli pracownicy pracują na wielu maszynach, czy cały obiekt osoby (wraz z obszernym text_blob, który przede wszystkim nie jest wymagany) będzie przesyłany przez sieć? Czy istnieje sposób, aby tego uniknąć?
  • W jaki sposób mogę wydajnie i równomiernie rozpowszechniać rekordy Person pracownikom działającym na wielu maszynach?

  • Czy to może być lepszy pomysł? Czy nie przytłoczyłoby bazy danych, gdyby osoba miała kilka milionów rekordów?

    # 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() 
    
+0

użyć opóźnienia zadania i ustawić timer dla tego – catherine

+0

@catherine, w jaki sposób timer mi w tym przypadku pomoże? –

+0

Przepraszam za ten czas mój błąd, to tylko opóźnienie zadania.Kiedy dana osoba ma miliony rekordów, seler odkłada zadania i zarządza nimi, wysyłając jeden po drugim – catherine

Odpowiedz

1

Tak. Jeśli w bazie danych znajdują się miliony rekordów, to prawdopodobnie nie jest to najlepsze podejście, ale ponieważ musisz przejrzeć wszystkie miliony rekordów, to bez względu na to, co zrobisz, Twój DB zostanie trafiony całkiem ciężko.

Oto kilka alternatyw, z których żaden nie nazwałbym "lepiej", po prostu inny.

  1. Zaimplementuj procedurę obsługi sygnału pre_save dla klasy Person, która obsługuje pliki .title(). W ten sposób twoja nazwa_wszystko/last_names zawsze będą poprawnie przechowywane w db, i nie będziesz musiał zrobić to ponownie.
  2. Użyj polecenia zarządzania, które pobiera jakiś parametr stronicowania ... być może użyj pierwszej litery nazwiska, aby posegmentować osoby. Tak więc uruchomienie ./manage.py my_task a zaktualizuje wszystkie rekordy, w których nazwisko zaczyna się od "a". Oczywiście musielibyśmy uruchomić to kilka razy, aby przejść przez całą bazę danych
  3. Może to zrobić za pomocą jakiegoś kreacyjnego sql. Nie zamierzam tu nawet próbować, ale warto byłoby zbadać sprawę.

Należy pamiętać, że .save() będzie trudniejszym "trafieniem" w bazę danych, a właściwie wybraniem milionów rekordów.

+0

tak więc .title() jest tu przykładową operacją, co chciałem wskazać przy jego pomocy, że nie wszystko, co obiekt ma, jest używane przez my_task(). –

+0

Oszczędności w partiach mogą zmniejszyć intesję "trafienia", nieprawdaż? Ale w jaki sposób mogę wydajnie wysłać go w partiach? –

10

Wierzę, że lepiej i bezpieczniej przekazać PK niż cały obiekt modelu. Ponieważ PK jest po prostu liczbą, serializacja jest znacznie prostsza. Co najważniejsze, możesz użyć bezpieczniejszego sarializera (json/yaml zamiast pickle) i mieć spokój ducha, że ​​nie będziesz miał problemów z serializacją swojego modelu.

Jak this artykuł mówi:

Od Seler jest rozproszony system, nie można wiedzieć, w którym proces, a nawet o tym, co maszyna zadanie zostanie uruchomione. Nie należy więc przekazywać obiektów modelu Django jako argumentów do zadań, a prawie zawsze lepiej jest ponownie pobrać obiekt z bazy danych, ponieważ wiążą się z nim warunki wyścigu.

Powiązane problemy