可以在 django 中异步执行数据库操作吗?

Mur*_*nio 5 django asynchronous python-asyncio

我正在编写一个命令来在数据库中随机创建 500 万个订单。

def constrained_sum_sample(
    number_of_integers: int, total: Optional[int] = 5000000
) -> int:
    """Return a randomly chosen list of n positive integers summing to total.

    Args:
        number_of_integers (int): The number of integers;
        total (Optional[int]): The total sum. Defaults to 5000000.

    Yields:
        (int): The integers whose the sum is equals to total.
    """

    dividers = sorted(sample(range(1, total), number_of_integers - 1))
    for i, j in zip(dividers + [total], [0] + dividers):
        yield i - j


def create_orders():
    customers = Customer.objects.all()
    number_of_customers = Customer.objects.count()
    for customer, number_of_orders in zip(
        customers,
        constrained_sum_sample(number_of_integers=number_of_customers),
    ):
        for _ in range(number_of_orders):
            create_order(customer=customer)
Run Code Online (Sandbox Code Playgroud)

number_of_customers将至少大于 1k 并且该create_order函数执行至少 5 次 db 操作(一个创建订单,一个随机获取订单的商店,一个创建订单项(最多可以达到 30 个,也是随机的),一个用于获取该项目的产品(或更高但等于该项目),另一个用于创建销售说明。

正如您可能怀疑这需要很长时间才能完成。我曾尝试异步执行这些操作,但未成功。我的所有尝试(至少有十多次;其中大多数使用sync_to_async)都引发了以下错误:

SynchronousOnlyOperation you cannot call this from an async context - use a thread or sync_to_async
Run Code Online (Sandbox Code Playgroud)

在我继续破头之前,我问:有可能实现我的愿望吗?如果是这样,我应该如何进行?

非常感谢!

Ahm*_*hab 5

尚未支持,但正在开发中。

Django 3.1 正式对视图和中间件提供异步支持,但是如果您尝试在异步函数中调用 ORM,您将得到 SynchronousOnlyOperation。

如果您需要从异步函数调用数据库,他们提供了帮助程序实用程序,例如:async_to_sync和sync_to_async以在线程或协程模式之间进行更改,如下所示:

from asgiref.sync import sync_to_async

results = await sync_to_async(Blog.objects.get, thread_sensitive=True)(pk=123)
Run Code Online (Sandbox Code Playgroud)

如果您需要对数据库的调用进行排队,我们曾经使用任务队列,例如 celery 或rabbitMQ。

  • 顺便说一句,如果您真的知道自己在做什么,则可以调用它,但您有责任关闭异步安全,但要注意数据丢失和完整性错误
#settings.py
DJANGO_ALLOW_ASYNC_UNSAFE=True
Run Code Online (Sandbox Code Playgroud)

Django 中需要这样做的原因是许多库,特别是数据库适配器,要求在创建它们的同一线程中访问它们。此外,许多现有的 Django 代码假设它们都在同一线程中运行,例如中间件添加事物到请求以便稍后在视图中使用。

发行说明中有更多有趣的消息: https://docs.djangoproject.com/en/3.1/topics/async/


小智 -2

您可以使用bulk_create()创建大量对象,这将加快进程,另外将bulk_create()放在单独的线程下。