2011-09-21 5 views
9

Muszę uruchamiać zadania na około 150k obiektów Django. Jaki jest najlepszy sposób na zrobienie tego? Używam Django ORM jako Broker. Bazą danych bazy danych jest MySQL oraz dławiki i matryce podczas task.delay() wszystkich zadań. Podobne, chciałem również oderwać to od złożenia formularza, ale wynikowe żądanie wygenerowało długi czas odpowiedzi, który upłynął.django/seler: Najlepsze praktyki do uruchamiania zadań na obiektach Django 150k?

+1

To jest ** dokładnie ** pytanie, które było mi potrzebne. Bardzo doceniane. – mlissner

Odpowiedz

10

Chciałbym również rozważyć użycie czegoś innego niż z wykorzystaniem bazy danych jako „pośrednik”. Naprawdę nie nadaje się do tego rodzaju pracy.

Choć można przenieść część tego narzutu z cyklu żądania/odpowiedzi poprzez uruchomienie zadanie stworzyć inne zadania:

from celery.task import TaskSet, task 

from myapp.models import MyModel 

@task 
def process_object(pk): 
    obj = MyModel.objects.get(pk) 
    # do something with obj 

@task 
def process_lots_of_items(ids_to_process): 
    return TaskSet(process_object.subtask((id,)) 
         for id in ids_to_process).apply_async() 

Ponadto, ponieważ prawdopodobnie nie ma 15000 procesorów do przetwarzania wszystkie z tych obiektów równolegle, można podzielić obiektów kawałkami powiedzieć, 100 lub 1000:

from itertools import islice 
from celery.task import TaskSet, task 
from myapp.models import MyModel 

def chunks(it, n): 
    for first in it: 
     yield [first] + list(islice(it, n - 1)) 

@task 
def process_chunk(pks): 
    objs = MyModel.objects.filter(pk__in=pks) 
    for obj in objs: 
     # do something with obj 

@task 
def process_lots_of_items(ids_to_process): 
    return TaskSet(process_chunk.subtask((chunk,)) 
         for chunk in chunks(iter(ids_to_process), 
              1000)).apply_async() 
+0

Dzięki pytaj! Dzięki @ApPeL i Twojej sugestii przeszedłem do brokera RabbitMQ i zobaczyłem natychmiastowe zyski. Ponadto, włączenie tych zadań ustaliło to, co próbowałem osiągnąć !! –

+0

Czy możesz skomentować, jak działa ten kod i ile zadań jest tworzonych? Próbowałem go przez ostatnie 4 dni i ciągle obniża moją bazę danych. Używam tylko 80% procesora, gdy jest uruchomiony, ale otrzymuję "MySQL zniknął" i łączę błędy po uruchomieniu przez chwilę. –

+0

Wygląda na to, że przeciążasz bazę danych? Czy przechowujesz wyniki w bazie danych? Jest to ustawienie domyślne dla django-selera. Jeśli ich nie potrzebujesz, powinieneś ustawić '@task (ignore_result = True)' lub wyłączyć je globalnie używając 'CELERY_IGNORE_RESULT = True' – asksol

1

używam beanstalkd (http://kr.github.com/beanstalkd/) jako silnika. Dodanie pracownika i zadania jest bardzo proste dla Django, jeśli użyjesz django-beanstalkd: https://github.com/jonasvp/django-beanstalkd/

Jest to bardzo niezawodny sposób użycia.

Przykład pracownika:

import os 
import time 

from django_beanstalkd import beanstalk_job 


@beanstalk_job 
def background_counting(arg): 
    """ 
    Do some incredibly useful counting to the value of arg 
    """ 
    value = int(arg) 
    pid = os.getpid() 
    print "[%s] Counting from 1 to %d." % (pid, value) 
    for i in range(1, value+1): 
     print '[%s] %d' % (pid, i) 
     time.sleep(1) 

Aby uruchomić zadania/pracownika/zadania:

from django_beanstalkd import BeanstalkClient 
client = BeanstalkClient() 

client.call('beanstalk_example.background_counting', '5') 

(źródło pochodzących z np app Django beanstalkd)

Enjoy!