2013-02-26 26 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() 

Nella mia applicazione da qualche parte ho qualcosa di simile:Le istanze dell'oggetto modello django devono essere passate al sedano?

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() 
  • sedano sottaceti p per inviarlo alla destra dei lavoratori?
  • Se i lavoratori sono in esecuzione su più macchine, l'oggetto dell'intera persona (insieme all'ingombro text_blob che non è principalmente richiesto) deve essere trasmesso sulla rete? C'è un modo per evitarlo?
  • Come distribuire in modo efficiente e uniforme i record di Persona ai lavoratori in esecuzione su più macchine?

  • Potrebbe essere un'idea migliore? Non sarebbe sopraffare il db se la persona ha qualche milione di record?

    # 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

utilizzare il ritardo di attività e impostare il timer per quello – catherine

+0

@catherine in che modo il timer può essere utile in questo caso? –

+0

Scusate per quel timer, mio ​​errore, è solo un ritardo dell'attività.Quando la persona ha milioni di record, il sedano ritarderà le attività e lo gestirà inviando uno alla volta – catherine

risposta

1

Sì. Se ci sono milioni di record nel database, questo probabilmente non è l'approccio migliore, ma dal momento che devi passare attraverso tutti i milioni di record, allora praticamente non importa quello che fai, il tuo DB sta per essere colpito piuttosto difficile.

Ecco alcune alternative, nessuna delle quali definirei "migliore", solo diversa.

  1. Implementare un gestore di segnale pre_save per la classe Person che esegue il file .title(). In questo modo il tuo first_name/last_names verrà sempre memorizzato correttamente nel db e non dovrai farlo di nuovo.
  2. Utilizzare un comando di gestione che richiede una sorta di parametro di paging ... forse utilizzare la prima lettera del cognome per segmentare le persone. Quindi eseguire ./manage.py my_task a aggiornerebbe tutti i record in cui il cognome inizia con "a". Ovviamente dovresti eseguirlo più volte per ottenere l'intero database
  3. Forse puoi farlo con qualche sql creativo. Non ho intenzione di tentare qui, ma potrebbe valere la pena indagare.

Ricordare che .save() sarà il "colpo" più duro sul database, quindi selezionando effettivamente i milioni di record.

+0

quindi il .title() è un esempio di operazione qui, quello che volevo indicare con il suo aiuto è che non tutto ciò che l'oggetto ha è usato da my_task(). –

+0

Il salvataggio in batch può ridurre l'intesità del "colpo", vero? Ma come posso inviarlo in lotti in modo efficiente? –

10

Credo sia meglio e più sicuro passare PK piuttosto che l'intero oggetto del modello. Poiché PK è solo un numero, la serializzazione è anche molto più semplice. Soprattutto, puoi usare un sarializzatore più sicuro (json/yaml invece di pickle) e avere la tranquillità di non avere problemi con la serializzazione del modello.

Come this articolo dice:

Dal sedano è un sistema distribuito, non si può sapere in quale processo, o addirittura su quello che la macchina verrà eseguita l'attività. Quindi non si dovrebbero passare oggetti modello Django come argomenti alle attività, è quasi sempre meglio recuperare nuovamente l'oggetto dal database, in quanto vi sono possibili condizioni di competizione.

Problemi correlati