【问题标题】:Django non-blocking save?Django非阻塞保存?
【发布时间】:2016-10-12 07:42:36
【问题描述】:

有没有办法在 django 中对模型调用 save(),而无需等待 db 的响应?
你可以考虑这个异步,虽然我需要的更少,因为异步调用通常会给你回调——我在这里不需要。
所以基本上我想要 -

SomeModel.objects.bulk_create([list of objects ]),每个说 1000 个对象,
没有这条线阻止我的代码。我的代码中的这些行将没有用处。
我正在寻找一些简单的东西,像 celery 这样的包装似乎提供的远不止这些......

【问题讨论】:

  • 将 celery 与 django 进行比较是苹果和橙子的比较。 Django 旨在确保正确保存所有数据或在无法保存时抛出异常。你本质上是在改变 django。但是,您仍然可以将这项工作传递给 celery 并完成它。
  • 问题是我需要在这个视图中记录每次访问的一些细节,我不希望它因为这个插入而变慢。对于这样一个简单的任务,Celery 似乎过于复杂,依赖太多

标签: django asynchronous save nonblocking


【解决方案1】:

截至 2016 年,Django 是一个工作的网络框架(目前,如果我们忽略 channels)将 HTTP 请求“作为参数”并尽快返回 HTTP 响应。

这种架构意味着框架中没有异步操作的概念。如果您想延迟保存并在不等待的情况下向用户返回响应,您可以:

  • 要么运行另一个线程/异步块(这对于数据库事务来说可能很乏味......);
  • IronWorker 等服务允许您将操作排队以运行异步 a.s.a.p ;
  • celery,这可能会为您的案例带来太多功能,但会比一些自制解决方案做得更好。

【讨论】:

  • 太糟糕了。我确实记得在某处读过其他数据库(如 mongoDB)确实具有“插入并继续”选项。所以我可能会用它来做这个。
【解决方案2】:

rq(Redis 队列)是异步操作的另一种选择(Maxime Lorant 在他的回答中提到的那些除外)。它使用 Redis 作为代理(持有任务的中间人),所以如果你已经在使用 Redis 或者你想将它添加到你的项目中,你应该考虑它。这是一个不错且简单的解决方案,比 celery 简单得多。还有django-rq一个简单的应用,为rq提供django集成。

更新: 总结cmets

django_rq 提供了一个启动工作进程的管理命令(rqworker)。任何放入队列的作业都将由该进程执行。您可以为每个对象发送一个作业到队列(作业将是一个在其参数中包含对象的函数,它将将该对象保存在数据库中)或收集对象列表并使用此列表发送作业。在第二种情况下,您需要将此列表临时存储在某个地方,这可能会很棘手。

使用 redis 临时存储对象(推荐)

我认为最稳健的方法是将对象序列化为 json 并将它们存储到 redis 列表中。然后定期检查它的长度,当它达到所需长度时,您可以将作业发送到在其参数中包含此列表的队列。

使用worker的内存来临时存储对象

您也可以将工作人员的 RAM 用作临时存储。这是因为工作进程有自己的内存。在这种情况下,主进程(runserver)创建一个带有对象的作业。该作业不会保存对象,它只是将其添加到列表中。您可以继续将对象附加到此列表中。由于作业是在worker进程中执行的,所以这个列表存在于worker的内存中。当它具有所需的长度时,您可以保存所有对象。

但是想象一下您创建多个工人的情况。在这种情况下,队列中的每个作业都将由当前空闲的工作人员挑选。因此,一些对象将被附加到 worker_1 内存中的列表中,一些其他对象将被添加到 worker_2 列表中,等等,您必须处理与工人一样多的列表。

【讨论】:

  • django自定义管理命令呢?不知道如何访问一个已经在运行的
  • 什么意思?能不能给个更详细的解释?
  • 运行一个 django 命令docs.djangoproject.com/en/1.10/howto/custom-management-commands,它将在后台运行并写入数据库
  • 这是我的观点,该命令已经在一个单独的进程中,我的观点是我如何与它“通信”,并将对象从我的视图代码发送到命令/rq 进程。从我的角度来看,我想发送一个要创建的对象,并且在进程(rq 或命令)获得 1000 个之后,它将批量插入它们。
  • 好的,我明白了。无需创建自定义命令。 django_rq 提供了一个启动工作进程的管理命令(rqworker)。放入队列中的任何任务都将由该进程执行。您可以将作业发送到每个对象的队列,也可以收集其中一些并发送带有列表的作业。在第二种情况下,您需要将此列表临时存储在某个地方,这可能会很棘手。我认为最可靠的方法是将对象序列化为 json 并将它们存储到 redis 列表中。然后定期检查它的长度并在长度为 1000 时发送作业。
猜你喜欢
  • 2014-02-17
  • 2018-01-04
  • 1970-01-01
  • 2016-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多