【问题标题】:Why does Django's "request_finished" signal block the response?为什么 Django 的“request_finished”信号会阻塞响应?
【发布时间】:2014-12-27 10:17:41
【问题描述】:

如果我有一个从网站到 Django 视图的 ajax 调用,我希望它返回一些响应并发送一个响应已完成的信号。我可能会使用这样的东西(睡眠只是为了证明一个观点——这可能是任何长时间运行的过程)。

from time import sleep

@receiver(request_finished)
def comment_added(sender, **kwargs):
    sleep(5)
    return

AJAX 响应将被阻止,直到“睡眠”完成,从而使用户体验变慢。这不是在一定程度上违背了使用信号的目的吗?

我知道我可以为此使用 Celery,我正计划这样做。但我想更好地理解信号。谢谢!

【问题讨论】:

    标签: python ajax django signals django-signals


    【解决方案1】:

    Django signals 不提供任何异步功能。

    当信号被发送时,所有的接收者都会在同一个线程中作为常规函数被触发。所有指令都在逐步执行。 Django 不会响应客户端,直到所有接收者都完成他们的工作。

    Django 信号与socket singals 没有任何共同之处,例如,您可以订阅某个事件并在不阻塞线程的情况下收听它。

    例如,这里是Model的django code的一部分:

        meta = cls._meta
        if not meta.auto_created:
            signals.pre_save.send(sender=origin, instance=self, raw=raw, using=using,
                                  update_fields=update_fields)
        with transaction.commit_on_success_unless_managed(using=using, savepoint=False):
            if not raw:
                self._save_parents(cls, using, update_fields)
            updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
    

    在代码singals.pre_save.send 中,所有接收器都被执行。在他们完成之前,python 不会继续下一行。

    正如您所提到的,django 最流行的解决方案是celery。 另一种方法是使用非阻塞服务器框架,例如tornado

    【讨论】:

    • 谢谢@stalk。就算都在一个线程上,“request_finished”这个名字不是说应该先发送响应,再处理信号吗?这将使 UI 速度更快,而无需其他线程。
    【解决方案2】:

    Django 信号不像操作系统信号那样作为异步回调实现。随着特定阶段/事件的完成,它们一个接一个地在同一个线程中运行。所有注册的信号都将在处理请求的线程中调用 - 将处理该请求所需的总处理时间相加。

    因此,从这个意义上说,signal 的名称可能会产生误导,但它仍然有效,因为在触发特定事件(或手动发送一些自定义信号的信号)时会调用信号处理程序。 p>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-24
      • 2016-08-02
      • 1970-01-01
      • 2012-08-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-13
      相关资源
      最近更新 更多