• en
  • Language: ru
  • Documentation version: 3

Доступ к базе данных

Django ORM - это синхронный код, поэтому если вы хотите получить к нему доступ из асинхронного кода, вам нужно сделать специальную обработку, чтобы убедиться, что его соединения закрываются должным образом.

Если вы используете SyncConsumer или что-то на его основе - например, JsonWebsocketConsumer - вам не нужно делать ничего особенного, поскольку весь ваш код уже работает в синхронном режиме, а Channels выполнит очистку за вас как часть кода SyncConsumer.

Однако если вы пишете асинхронный код, вам необходимо вызывать методы базы данных в безопасном, синхронном контексте, используя database_sync_to_async.

Подключения к базе данных

Каналы потенциально могут открывать гораздо больше соединений с базой данных, чем вы привыкли, если вы используете потоковые потребители (синхронные) - они могут открывать до одного соединения на поток.

Если вы хотите контролировать максимальное количество используемых потоков, установите переменную окружения ASGI_THREADS на максимальное число, которое вы хотите разрешить. По умолчанию количество потоков устанавливается на «количество CPU * 5» для Python 3.7 и ниже, и min(32, os.cpu_count() + 4) для Python 3.8+.

Чтобы избежать слишком большого количества потоков, простаивающих в соединениях, вы можете переписать свой код для использования асинхронных потребителей и использовать потоки только тогда, когда вам нужно использовать ORM Django (используя database_sync_to_async).

база данных_sync_to_async

channels.db.database_sync_to_async - это версия asgiref.sync.sync_to_async, которая также очищает соединения с базой данных при выходе.

Чтобы использовать его, напишите свои ORM-запросы в отдельной функции или методе, а затем вызовите его с помощью database_sync_to_async, как показано ниже:

from channels.db import database_sync_to_async

async def connect(self):
    self.username = await database_sync_to_async(self.get_name)()

def get_name(self):
    return User.objects.all()[0].name

Вы также можете использовать его в качестве декоратора:

from channels.db import database_sync_to_async

async def connect(self):
    self.username = await self.get_name()

@database_sync_to_async
def get_name(self):
    return User.objects.all()[0].name