Найти - Пользователи
Полная версия: Django и несколько процессов
Начало » Django » Django и несколько процессов
1 2
vvpoloskin
Добрый день!
Нужен совет экспертов.
Хочу сделать os.fork() из view, но порожденный процесс приобретает все открытые дескрипторы родителя, в том числе и WSGI-сокет. При попытке прибить все открытые дескрипторы в дочернем процессе получаю ошибку сокета WSGI мол не работает.

Нужно отцепить от django код именно отдельным процессом.

Если более подробно:

def view(request):
   ...
   if not os.fork():
      target()
   return
def target(*args, **kwargs):
   ...
   sd = socket.socket(*args, **kwargs)
   sd.bind(*args)
   sd.listen()
   nsd = sd.accept()
  ...
Lexander
Используйте модуль subprocess или mutliprocessing или python-daemon.
Или запускайте второй процесс по крону, например, с помощью pycron.
Или используйте Celery.

Зависит от нюансов задачи.
JOHN_16
vvpoloskin
Для запуска дочерних приложений в общих целей предпочтительнее subprocess
subprocess.Popen(...., close_fds=True, ...)
Если аргументу close_fds присвоено значение True, то все дескрипторы, исключая 0, 1 и 2 будут закрыты перед выполнением дочернего процесса (только для UNIX).

Однако не факт что для вашей задачи это подойдет. Если не выйдет, присмотритесь к сообщению Lexander
vvpoloskin
Celery не очен
JOHN_16
vvpoloskinДля запуска дочерних приложений в общих целей предпочтительнее subprocess

Popen не проходит, так как хочу запускать не отдельный скрипт, а импортировать функционал из другого модуля.
Может быть кто знает, как в multiprocessing задать опцию, аналогичную close_fds=True в subprocess?
vvpoloskin
Так, уже лучше. Выяснилось, что если делаешь форк на девелоперском сервере, вся дочерний процесс наследует все файловые дескрипторы, а Django при обработке запроса посылает во все эти дескрипторы.
Таким образом даже если из дочернего процесса принудительно закрывать отнаследованные файловые дескрипторы, Django будет пытаться писать в закрытый сокет и все рухнет.

Может быть кто-то меня прокоментирует или поправит?
vvpoloskin
Ну народ, неужели никто не знает, как тупо сделать fork в Django, чтоб работало на девелоперском сервере?
Lexander
Тупо сделать форк в Джанго - это не работает.
Потому что это архитектурная ошибка, которую вы допускаете.

Файловые дескрипторы (и сокеты в том числе) не работают напрямую в создаваемом мультипроцессорном окружении. По своей сути. Это эксклюзивно блокируемый ресурс.
Есть простое правило, по которому можно заранее знать (или узнать), что будет работать, а что нет.
Если объект может быть сериализирован с помощью pickle, то его можно передавать между процессами, иначе - он потребует специальной обработки.
Для сокетов, соединений с БД, файлов и т.п.
Примером специальной обработки может быть закрытие и открытие заново соединения.

Поэтому для общения между родительским и дочерним процессом используются очереди и пайпы.
Для их реализации используют удобные системы-обертки типа Celery.
А для управления передачей данных (объектов) используются менеджеры, обеспечивающие эксклюзивный доступ к данным (объектам), следят за их доступностью (сокет открыт/закрыт) и т.п.

Пример
http://dickbrouwer.com/post/32405801335/django-zeromq-and-celery-multiprocessing-gotcha

ЗЫ
Если у вас возникает ошибка
IOError: sys.stdout access restricted by mod_wsgi
обновите mod_wsgi.
vvpoloskin
Lexander
Файловые дескрипторы (и сокеты в том числе) не работают напрямую в создаваемом мультипроцессорном окружении. По своей сути. Это эксклюзивно блокируемый ресурс.
Есть простое правило, по которому можно заранее знать (или узнать), что будет работать, а что нет.
Если объект может быть сериализирован с помощью pickle, то его можно передавать между процессами, иначе - он потребует специальной обработки.
Для сокетов, соединений с БД, файлов и т.п.
Примером специальной обработки может быть закрытие и открытие заново соединения.

Супер, но мне не нужно использовать ни сокеты, ни открытые файловые дескрипторы в дочернем процессе. Не нужно вообще ничего из этого. Просто если я делаю os.fork() и далее свой код - получаю Port 8000 already in use, что в полне логично. Если я в потомке делаю что-то вроде os.closerange(3, 1024), получаю WSGI-error Bad file descriptor и страница при загрузке бесконечно долго висит, пока не остановишь загрузку в браузере. Как-нибудь это побороть все же можно?
JOHN_16
vvpoloskin
Popen не проходит, так как хочу запускать не отдельный скрипт, а импортировать функционал из другого модуля.
можно передать рабочую директорию в дочерний процесс, и импортировать модуль.
А вообще помоему уже нужно более открыто говорить о поставленной задаче, а то складывается впечатление что задача у вас поставленна некорректно.
vvpoloskin
Хорошо, моя задача состоит в следующем:
из Django мне нужно запускать некоторую внешнюю программу-сервер, которая будет работать некоторое количество времени, конфигурационный файл этой программы создается на основе данных, введенных пользователем в форме. Также вместе с этой программой нужно запускать самописный сокет-сервер, который будет обрабатывать вывод программой.

Хотелось бы запускать внешнюю программу путем fork() и Popen в нем, а также отдельным потоком от вновь порожденного процесса стартовать собственно сокет-сервер.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB