2010-11-27 12 views
8

Piszę aplikację, która pozwoli użytkownikowi przesłać dane do pliku; aplikacja przetworzy te dane i prześle je użytkownikom. Przetwarzanie może zająć trochę czasu, więc chciałbym poradzić sobie z tym oddzielnie w skrypcie w języku Python, zamiast czekać w widoku, aby go ukończyć. Skrypt i widok w języku Python nie muszą się komunikować, ponieważ skrypt pobierze dane z pliku zapisanego w widoku. Widok wyświetli komunikat "Dziękujemy za przesłanie danych - wyniki zostaną przesłane pocztą e-mail"Django: Czy powinienem rozpocząć osobny proces?

Jaki jest najlepszy sposób na zrobienie tego w Django? Oddziel się od oddzielnego procesu? Umieścić coś w kolejce?

Przykładowy kod byłby bardzo doceniony. Dzięki.

+0

co jeśli wystąpi jakiś błąd, podczas przetwarzania danych? –

+0

Wyślę im e-mail na ten temat. Nie mogę oczekiwać, że będą czekać na stronie, dopóki jej nie skończę, ponieważ może to trwać 20 minut lub dłużej. – FunLovinCoder

Odpowiedz

17

Najprostszym możliwym rozwiązaniem jest napisanie zwyczaj commands że wyszukuje wszystkie nie przetworzone pliki, przetwarza je, a następnie wysyła e-mailem do użytkownika. Komendy zarządzania są uruchamiane wewnątrz struktury Django, dzięki czemu mają dostęp do wszystkich modeli, połączeń db, itp., Ale możesz wywoływać je z dowolnego miejsca, na przykład crontab.

Jeśli zależy Ci na czasie między przesłaniem pliku i rozpoczęciem przetwarzania, możesz użyć architektury takiej jak Celery, która jest po prostu biblioteką pomocniczą do korzystania z kolejki komunikatów i uruchamiania pracowników nasłuchujących w kolejce. Byłoby to dość małe opóźnienie, ale z drugiej strony prostota może być dla ciebie ważniejsza.

Zdecydowanie zaleciłbym, aby wątki i procesy odradzania nie były wyświetlane w widokach, ponieważ wątki działają w procesie django i mogą zniszczyć serwer WWW (w zależności od konfiguracji). Proces potomny dziedziczy wszystko od procesu Django, czego prawdopodobnie nie chcesz. Lepiej trzymać te rzeczy oddzielnie.

+0

Tak, chcę, aby było to tak proste, jak to możliwe, ale nie zdawałem sobie sprawy, że wyniki tarła procesu lub wątku mogą być tak poważne. Dzięki za heads up. – FunLovinCoder

+0

+1 dla selera. Kolejki są sposobem, aby przejść tutaj. –

3

Można wykonać odradzanie thread, aby wykonać przetwarzanie. To nie miałoby wiele wspólnego z Django; funkcja widoku musiałaby uruchomić wątek roboczy i to wszystko.

Jeśli naprawdę chcesz osobny proces, potrzebujesz modułu subprocess. Ale czy naprawdę potrzebujesz przekierować standardowe wejścia/wyjścia lub zezwolić na zewnętrzną kontrolę procesu?

Przykład:

from threading import Thread 
from MySlowThing import SlowProcessingFunction # or whatever you call it 

# ... 

Thread(target=SlowProcessingFunction, args=(), kwargs={}).start() 

nie zrobiłem program, w którym nie chcesz śledzić postępy nitek, więc nie wiem, czy to działa bez zapisywania obiektu Thread gdzieś. Jeśli trzeba zrobić, to całkiem proste:

allThreads = [] 

# ... 

global allThreads 
thread = Thread(target=SlowProcessingFunction, args=(), kwargs={}) 
thread.start() 
allThreads.append(thread) 

Można usunąć wątki z listy podczas thread.is_alive() powraca False:

def cull_threads(): 
    global allThreads 
    allThreads = [thread for thread in allThreads if thread.is_alive()] 
+0

Po prostu potrzebuję uruchomić skrypt Pythona i zapomnieć o tym. Nie muszę się z nią komunikować, ponieważ pobierze dane z pliku, który napisałem w widoku. Czy mógłbyś dodać przykładowy kod? – FunLovinCoder

+0

Czy jest to całkowicie oddzielny skrypt w języku Python, czy można go zaimportować jako moduł i nazwać go? –

+0

@Mike DeSimone. Jest to całkowicie oddzielny skrypt Pythona, ale po sprzężeniu z knutin prawdopodobnie najlepiej nie spawnować proca lub wątku. – FunLovinCoder

4

Mam obecnie projekt o podobnych wymaganiach (po prostu bardziej skomplikowany ^^).

Nigdy nie odradza się podprocesu lub wątku z widoku Django. Nie masz kontroli nad procesami Django i może to być zabite, wstrzymane itp. Przed zakończeniem zadania. Jest kontrolowany przez serwer WWW (np. Apache przez WSGI).

Co chciałbym zrobić, to skrypt zewnętrzny, który działałby w osobnym procesie.Masz dwa rozwiązania, które moim zdaniem:

  • Proces, który zawsze działa i indeksuje katalog, w którym umieszczasz pliki. Sprawdzałoby to na przykład katalog co dziesięć sekund i przetwarzało pliki
  • To samo co powyżej, ale uruchamiane przez crona co x sekund. Zasadniczo ma taki sam efekt, jak
  • Użyj Celery, aby utworzyć procesy robocze i dodać zadania do kolejki za pomocą aplikacji Django. Następnie musisz odzyskać wyniki za pomocą jednego ze środków dostępnych w Celery.

Teraz prawdopodobnie trzeba uzyskać dostęp do informacji w modelach Django na e-mail użytkownika w końcu. Tutaj masz kilka rozwiązań:

  • importować moduły (modele itp) ze skryptu zewnętrznego
  • Wdrożenie skryptu zewnętrznego jako polecenia niestandardowego (jak knutin sugerowane)
  • przekazuje wyniki do aplikacji Django poprzez żądanie POST na przykład. Następnie wykonasz wysyłanie wiadomości e-mail i zmiany statusu itp. W normalnym widoku Django.

Chciałbym wybrać proces zewnętrzny i zaimportować moduły lub żądanie POST. W ten sposób jest znacznie bardziej elastyczny. Można na przykład wykorzystać moduł przetwarzania wieloprocesowego do przetworzenia kilku plików w tym samym czasie (dzięki temu wydajnie wykorzystując maszyny wielordzeniowe).

Podstawowy przepływ pracy będzie:

  1. Sprawdź katalog dla nowych plików
  2. Dla każdego pliku (może być parallelized):
    1. Process
    2. Wyślij e-mail lub zawiadomić aplikację Django
  3. Spij przez chwilę

Mój projekt zawiera naprawdę wymagające procesora przetwarzanie. Obecnie korzystam z zewnętrznego procesu, który nadaje zadania przetwarzania do puli procesów roboczych (w zasadzie to, co może zrobić dla ciebie Celery) i raportuje postępy i wyniki z powrotem do aplikacji Django za pośrednictwem żądań POST. Działa bardzo dobrze i jest względnie skalowalny, ale wkrótce go zmienię, aby używać Selera w klastrze.

+0

Dzięki za świetne opinie. Być może będę musiał uruchomić wiele wątków dla dużych plików, tak by spojrzeć na moduł wieloprocesowy. – FunLovinCoder

+0

Jeśli przetwarzanie jest ograniczone przez procesor, należy użyć procesów (np. Z modułem przetwarzania), a nie wątków (moduł wątków). Globalna blokada interpretera Pythona zapobiega działaniu wątków równolegle, więc nie ma wzrostu wydajności (zdałem sobie z tego sprawę podczas wykonywania mojego projektu). –

+0

Również Seler może być drogą do zrobienia, ponieważ wykonuje dużo pracy opisanej automatycznie. Jedyne, co musisz zrobić, to dowiedzieć się, jak uzyskać wyniki, ponieważ nie możesz się doczekać zakończenia zadania (wywołanie zwrotne HTTP może zrobić to z łatwością). –

1

Można użyć przetwarzania wieloprocesowego. http://docs.python.org/library/multiprocessing.html

Zasadniczo

def _pony_express(objs, action, user, foo=None): 
    # unleash the beasts 

def bulk_action(request, t): 

    ... 
    objs = model.objects.filter(pk__in=pks) 

    if request.method == 'POST': 
     objs.update(is_processing=True) 

     from multiprocessing import Process 
     p = Process(target=_pony_express, args=(objs, action, request.user), kwargs={'foo': foo}) 
     p.start() 

     return HttpResponseRedirect(next_url) 

    context = {'t': t, 'action': action, 'objs': objs, 'model': model} 
    return render_to_response(...) 
Powiązane problemy