Параллельная сериализация в Django REST Framework? Или другие способы ускорения сериализации моделей? - PullRequest
1 голос
/ 04 февраля 2020

Разрабатываемое мной приложение должно доставлять список объектов ORM пользователю через конечную точку REST. Список объектов большой - до 500 или 600 одновременно (нумерация страниц не предусмотрена).

Модель выглядит примерно так:

class PositionItem(models.Model):
    account = models.ForeignKey(core_models.Portfolio, on_delete=models.CASCADE)
    macro_category = models.ForeignKey(MacroCategory, on_delete=models.SET_NULL, null=True)
    category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)
    sub_category = models.ForeignKey(SubCategory, on_delete=models.SET_NULL, null=True)

Я начал использовать стандарт ModelSerializer с установленным many=True, но это было очень медленно - до 12 секунд для сериализации всех объектов. Я сократил время выполнения на несколько секунд, предварительно выбрав / кэшировав внешние ключи, необходимые для конечной точки, методом .select_related(), и еще пару секунд, заменив ModelSerializer пользовательской функцией сериализатора, которая просто сопоставляет поля с словарь без каких-либо затрат на проверку. Тем не менее, это все еще медленно (6-7 секунд), и я хотел бы оптимизировать дальше. Я думал о попытке распараллелить сериализатор вместо этого, но у меня возникли некоторые проблемы с реализацией.

Мой пользовательский сериализатор выглядит так:

def serialize_position_record(record):

    account = record.account
    macro_category = record.macro_category
    category = record.category
    sub_category = record.sub_category

    return {
        'account': account.portfolio_id,
        'macro_category': macro_category.macro_category,
        'category': category.category,
        'sub_category': sub_category.sub_category,
        'sorting': {
            'macro_category': macro_category.sort_order,
            'category': category.sort_order,
            'sub_category': sub_category.sort_order

        }
    }

Я пробовал multiprocessing с Pool:

import multiprocessing
import models
import utils

items = models.Item.objects.select_related().filter(account__user=user)
pool = multiprocessing.Pool(4)
serialized_items = pool.map(utils.serialize_position_record, items)

но это зависает не менее 60 секунд (вероятно, больше, я убил его, прежде чем он что-либо возвратил).

Я также пытался использовать многопоточность с помощью multiprocessing.dummy API:

import multiprocessing
import models
import utils

items = models.Item.objects.select_related().filter(account__user=user)
pool = multiprocessing.dummy.Pool(4)
serialized_items = pool.map(utils.serialize_position_record, items)

но я получаю исключения:

Traceback (most recent call last):
  File "/Users/xx/venvs/web-portal/lib/python3.7/site-packages/django/db/models/fields/related_descriptors.py", line 164, in __get__
    rel_obj = self.field.get_cached_value(instance)
  File "/Users/xx/venvs/web-portal/lib/python3.7/site-packages/django/db/models/fields/mixins.py", line 13, in get_cached_value
    return instance._state.fields_cache[cache_name]
KeyError: 'sub_category'

и

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/xx/venvs/web-portal/lib/python3.7/site-packages/django/db/backends/utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
psycopg2.errors.UndefinedTable: relation "reports_subcategory" does not exist
LINE 1: ...", "reports_subcategory"."sort_order" FROM "reports_s...

Так что я не знаю, что делать. Я не пишу много параллельного кода - я пишу что-то неправильно? Или есть лучший способ оптимизировать этот процесс помимо распараллеливания? Я достиг потолка для производительности? Я также использую django -пользователей, так как это мультитенантное приложение - не уверен, что это способствует ошибке отношения не существует.

Есть идеи?

1 Ответ

1 голос
/ 04 февраля 2020

Рассмотрите возможность использования сторонних библиотек сериализации, таких как serpy и marshmallow . Оба утверждают, что обеспечивают существенное улучшение скорости по сравнению с собственными сериализаторами Django Rest Framework.

Serpy предоставляет некоторые подробные тесты в своих документах.

Serialization Times According to Serpy

Обе библиотеки достаточно интуитивно понятны, если вы уже знакомы с сериализаторами в Django Rest Framework.

...