Как справиться со слишком большим количеством открытых файловых дескрипторов в Python/Django?

Мое приложение Django имеет несколько моделей, которые имеют некоторые поля файлов:

class MyModelA(models.Model):
    field1 = models.FileField(...)
    field2 = models.FileField(...)
    field3 = models.FileField(...)

class MyModelB(models.Model):
    field1 = models.FileField(...)
    field2 = models.FileField(...)
    field3 = models.FileField(...)

Чтобы сгенерировать некоторые тестовые данные для моего приложения, которые включают поддельные файлы, я делаю следующее:

my_app/management/commands/generatetestdata.py:

class Command(BaseCommand):
    def handle(self, *args, **options):
        self.generate_model_a_test_data()
        self.generate_model_b_test_data()
        ...

    def generate_model_a_test_data(self):
        field1_data = Path("/path/to/field1/sample/file").read_bytes()
        field2_data = Path("/path/to/field2/sample/file").read_bytes()

        for _ in range(1000):
            instances = []

            instances.append(MyModelA(
                field1=ContentFile(field1_data, name="Some File Name"),
                field2=ContentFile(field2_data, name="Some File Name"),
            ))

            MyModelA.objects.bulk_create(instances)

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

Есть только несколько реальных файлов, которые я считываю из файловой системы. Я считываю их в память и создаю тонну экземпляров ContentFile, которые при сохранении фактически копируют эти файлы в мой каталог мультимедиа. Да, это не так эффективно, как использование чего-то вроде симлинков, но это нормально.

Проблема заключается в том, что иногда запуск python manage.py generatetestdata приводит к успеху, а в других случаях через несколько минут происходит сбой: django.db.utils.OperationalError: unable to open database file

Когда он не работает, это происходит после создания тысяч файлов (НЕ сразу после выполнения команды), так что это точно не проблема с правами.

Я подозреваю, что причина неудачи в том, что у Python слишком много открытых дескрипторов файлов, хотя я не совсем уверен, как это подтвердить.

Мой вопрос заключается в следующем: Как я могу сделать так, чтобы мой код закрывал эти файловые дескрипторы по мере выполнения, а не ждал, пока это сделает сборщик мусора? Похоже, что ожидание, пока GC сделает это, не работает.

Я пробовал что-то вроде этого:

    def generate_model_a_test_data(self):
        field1_data = Path("/path/to/field1/sample/file").read_bytes()
        field2_data = Path("/path/to/field2/sample/file").read_bytes()

        for _ in range(1000):
            instances = []

            with ContentFile(field1_data, name="Some File Name") as cf1:
                with ContentFile(field2_data, name="Some File Name") as cf2:
                    instances.append(MyModelA(
                        field1=cf1,
                        field2=cf2,
                    ))

            MyModelA.objects.bulk_create(instances)

но это не помогло. Этот код с менеджерами контекста не падает, и правильно присоединяет данные файла к экземплярам модели, но все равно падает, если я создаю слишком много экземпляров модели.

Есть ли способ подтвердить, что проблема заключается в слишком большом количестве открытых дескрипторов файлов, а затем каким-то образом заставить код закрыть их?

Вернуться на верх