Доступ к базе данных¶
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