Как правильно использовать модуль многопроцессорности в Django?

У меня есть программа на python 3.8+, использующая Django и Postgresql, которая требует нескольких потоков или процессов. Я не могу использовать потоки, так как GLI ограничивает их одним процессом, что приводит к ужасной производительности (особенно учитывая, что большинство потоков привязаны к процессору).

Поэтому очевидным решением было использование модуля мультипроцессинга. Но я столкнулся с несколькими проблемами:

  1. При использовании spawn для создания новых процессов я получаю ошибку "Apps are not loaded yet", когда новый процесс импортирует модели Django. Это происходит потому, что новый процесс не имеет соединения с базой данных, переданного основному процессу с помощью python manage.py runserver. Я обошел эту проблему, используя fork вместо spawn (как советуют здесь), так что соединения копируются в другие процессы, но я чувствую, что это не лучшее решение и должен быть чистый способ запуска новых процессов с необходимыми соединениями.

  2. Когда несколько процессов одновременно обращаются к базе данных, иногда выдаются ложные результаты (частично даже от неправильных моделей/отношений), что приводит к краху программы. Это может произойти при начальном запуске при получении данных, но также и во время работы программы. Я пытался использовать ISOLATION LEVEL SERIALIZABLE (как советуют здесь), добавив его в опции в настройках базы данных, но это не помогло.
    Возможным решением может быть использование пользовательских блокировок, которые даются каждому процессу, но это тоже не кажется хорошим решением.

В общем, вопрос в следующем: есть ли хороший и чистый способ использовать многопроцессорность в Django без этих проблем? Способ, при котором новые процессы получают соединения с базой данных без необходимости полагаться на fork, и все процессы могут просто получить доступ к базе данных без каких-либо условий гонки, иногда дающих ложные результаты, как это?

Один важный момент: я не использую пул, поскольку процессы не выполняют одну и ту же простую задачу. Процессы выполняют различные специфические задачи, обмениваются данными через многопроцессорные сигналы, очереди, значения и пространства имен (разделяемая память), и новые процессы могут быть вызваны взаимодействием с пользователем (websockets)
. Я пытался изучить Celery, так как его рекомендовали на много вопросов о Django и мультипроцессинге, но я не знаю, как использовать что-то подобное в структуре проекта с конкретными различными процессами, которые должны быть созданы в определенные моменты, и данными, которые передаются через Queues, Signals, Values и Namespaces в существующем проекте.

Спасибо, что прочитали; любая помощь будет оценена по достоинству!

Перед каждым новым процессом сначала вызывается функция настройки, вызывающая Django.setup(), прежде чем выполнить настоящую функцию. Я надеялся, что таким образом каждый процесс будет создавать независимое соединение с базой данных, чтобы текущая система могла работать.

Да - вы можете сделать это с помощью initializer, как объяснено в моем другом ответе от прошлого.

Однако, он по-прежнему выдает ошибки типа django.db.utils.OperationalError: потеряна синхронизация с сервером: получено сообщение типа "1", длина 976434746

.

Это означает, что вы используете метод запуска fork для подпроцессов, и любые соединения с базой данных и их состояние были перенесены в подпроцессы, и они будут рассинхронизированы при использовании несколькими процессами.

Вам нужно закрыть их:

def subprocess_setup():
    django.setup()
    from django.db import connections
    for conn in connections.all():
        conn.close()
    
with ProcessPoolExecutor(max_workers=5, initializer=subprocess_setup) as executor:
   
Вернуться на верх