Джанго: Должен ли я начать отдельный процесс? - PullRequest
8 голосов
/ 27 ноября 2010

Я пишу приложение, которое позволит пользователю загружать данные в файл; приложение обработает эти данные и отправит результаты по электронной почте пользователю. Обработка может занять некоторое время, поэтому я хотел бы обработать это отдельно в скрипте Python, а не ждать в представлении, чтобы он завершился. Скрипт Python и представление не должны взаимодействовать, так как скрипт будет извлекать данные из файла, написанного представлением. Представление просто выведет сообщение типа «Спасибо за загрузку ваших данных - результаты будут отправлены вам по электронной почте»

Какой лучший способ сделать это в Джанго? Возродить отдельный процесс? Поставить что-нибудь в очередь?

Некоторые примеры кода будут с благодарностью. Спасибо.

Ответы [ 4 ]

17 голосов
/ 27 ноября 2010

Самое простое возможное решение - написать пользовательские команды , которые ищут все необработанные файлы, обрабатывают их и затем отправляют пользователю электронное письмо.Команды управления выполняются внутри инфраструктуры Django, поэтому они имеют доступ ко всем моделям, соединениям БД и т. Д., Но вы можете вызывать их откуда угодно, например, crontab.

Если вы заботитесь о временном интервале между файлами,После загрузки и обработки вы можете использовать такую ​​среду, как Celery , которая в основном является вспомогательной библиотекой для использования очереди сообщений и запуска рабочих, прослушивающих очередь.Это будет довольно низкая задержка, но с другой стороны, простота может быть более важной для вас.

Я бы настоятельно рекомендовал не запускать потоки или порождать процессы в ваших представлениях, так как потоки будут работать внутри django.процесс и может уничтожить ваш веб-сервер (в зависимости от вашей конфигурации).Дочерний процесс унаследует все от процесса Django, чего вы, вероятно, не хотите.Лучше хранить это отдельно.

4 голосов
/ 27 ноября 2010

В настоящее время у меня есть проект с аналогичными требованиями (только более сложный ^^).

Никогда не порождайте подпроцесс или поток из вашего представления Django.У вас нет контроля над процессами Django, и он может быть убит, приостановлен и т.д. до конца задачи.Он управляется веб-сервером (например, через Apache через WSGI).

Я бы сделал внешний сценарий, который будет выполняться в отдельном процессе.Я думаю, у вас есть два решения:

  • Процесс, который всегда работает и сканирует каталог, в который вы помещаете свои файлы.Например, он будет проверять каталог каждые десять секунд и обрабатывать файлы
  • То же, что и выше, но запускаться cron каждые x секунд.Это в основном имеет тот же эффект
  • Используйте Celery для создания рабочих процессов и добавления заданий в очередь с вашим приложением Django.Затем вам нужно будет вернуть результаты одним из способов, доступных в Celery.

Теперь вам, вероятно, потребуется получить доступ к информации в моделях Django, чтобы в итоге отправить электронное письмо пользователю.Здесь у вас есть несколько решений:

  • Импорт ваших модулей (моделей и т. Д.) Из внешнего скрипта
  • Реализация внешнего скрипта как пользовательской команды (как предложил Кнутин)
  • Сообщите результаты в приложение Django, например, через запрос POST.Затем вы выполняете отправку электронной почты, изменения статуса и т. Д. В обычном представлении Django.

Я бы пошел на внешний процесс и импортировал модули или запрос POST.Таким образом, это намного более гибко.Например, вы можете использовать многопроцессорный модуль для одновременной обработки нескольких файлов (таким образом, эффективно используя многоядерные машины).

Базовый рабочий процесс будет:

  1. Проверкакаталог для новых файлов
  2. Для каждого файла (может быть распараллелен):
    1. Процесс
    2. Отправка электронной почты или уведомление о вашем приложении Django
  3. Спи на время

Мой проект содержит действительно процессорозатратную обработку.В настоящее время я использую внешний процесс, который дает задания обработки пулу рабочих процессов (это в основном то, что Celery может сделать для вас) и сообщает о ходе выполнения и результатах обратно в приложение Django через запросы POST.Он работает очень хорошо и является относительно масштабируемым, но я скоро заменю его на использование Celery в кластере.

3 голосов
/ 27 ноября 2010

Вы можете создать поток , чтобы выполнить обработку. Это не имело бы большого отношения к Джанго; функция представления должна была бы запустить рабочий поток, и все.

Если вы действительно хотите отдельный процесс, вам понадобится модуль подпроцесс . Но вам действительно нужно перенаправить стандартный ввод-вывод или разрешить внешнее управление процессом?

Пример:

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

# ...

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

Я не создавал программу, в которой я не хотел бы отслеживать продвижение потоков, поэтому я не знаю, работает ли это без сохранения где-либо объекта Thread. Если вам нужно это сделать, это довольно просто:

allThreads = []

# ...

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

Вы можете удалить темы из списка, когда thread.is_alive() вернет False:

def cull_threads():
    global allThreads
    allThreads = [thread for thread in allThreads if thread.is_alive()]
1 голос
/ 12 января 2011

Вы можете использовать многопроцессорность.http://docs.python.org/library/multiprocessing.html

По существу,

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(...)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...