【问题标题】:Is Django post_save signal asynchronous?Django post_save 信号是异步的吗?
【发布时间】:2012-08-07 14:29:17
【问题描述】:

我有一个like 功能,就像社交网络一样或点赞功能;用户点击星/心/任何东西来标记内容为喜欢。它是用ajax完成的,必须很快。

这里唯一的问题是,由于某些原因,我必须为每个 like 执行一些任务,我发现它们是直接在 like 视图中编码的,这使得它变慢了。

我正在考虑使用信号来异步执行这些任务,以便视图可以立即将json 发送回javascript,而无需等待任务完成。

我开始为 like 创建一个信号,但后来意识到 Django 的 signals 不是异步的,它最终会是一样的,视图必须等待信号完成才能发回它的响应。

所以我可以尝试使 signal 异步,正如这里和那里所解释的那样,但我也将 post_save 信号用于 like 模型,但现在我想知道视图是否可以在信号之前完成被处决?

【问题讨论】:

  • 直接回答:不,是同步的。

标签: django signals


【解决方案1】:

async-signals 包 (https://github.com/nyergler/async-signals) 抽象了这个问题。您调用异步信号函数;如果 Celery 存在,则包使用它从工作人员异步发出信号;如果 Celery 不可用,则包以传统的同步方式发送信号。

【讨论】:

    【解决方案2】:

    还可以查看celery(或更具体地说是django-celery)。它是一个异步任务调度程序/处理程序。因此,您的 post_save 信号处理程序创建了一个任务,该任务通过 celery 拾取并执行。这样,即使在不同的机器或一批机器上,您仍然可以快速执行应用程序,同时异步执行繁重的工作。

    【讨论】:

    • 我相信这现在应该是公认的答案!如果有其他选项可用,我总是建议不要在代码库中引入多线程,Chris 发布的代码确实显示了easy 的冰山一角,但在引入多线程时没有提到所有可能的问题。
    • 拜托,STOP 推荐使用 celery 来完成那些简单的跑跑任务。
    • @Symon 我很久以前就不再推荐芹菜了。我上一次建议 研究芹菜大约是 9 年前。如果您如此反对这种解决方案,至少与读者分享您认为他们不应该使用 celery 的原因。另外,请停止告诉人们(不)做什么。你的评论是对我个人的攻击,而不是提供任何见解。只需提供您的意见,并留给读者来确定最适合他们需要的内容。更好的是,提供一个解决方案并解释为什么它比其他解决方案更好。
    • 我很想知道 2021 年芹菜是不是/为什么比最初写这个答案时更糟糕的选择。
    【解决方案3】:

    你想要的是一个线程。它们非常易于使用。你只需继承threading.Thread 并编写一个run 方法:

    import threading
    
    class LikeThread(threading.Thread):
        def __init__(self, user, liked, **kwargs):
            self.user = user
            self.liked = liked
            super(LikeThread, self).__init__(**kwargs)
    
        def run(self):
            # long running code here
    

    然后,当您准备好执行任务时,您可以使用:

    LikeThread(request.user, something).start()
    

    您的视图代码的其余部分或任何将恢复并返回响应的内容,线程将愉快地完成其工作,直到完成然后自行结束。

    查看完整文档:http://docs.python.org/library/threading.html

    【讨论】:

    • 这很有趣;但我的印象是python下的线程受GIL限制?
    • 嗯,当然。如果你不想改变任何东西,这不是问题。如果您只是发送包含数据的电子邮件等。如果您需要实际修改任何内容并且可能存在潜在的线程安全问题,那么您需要明智地使用锁。尽管如此,如果你需要卸载一个长时间运行的进程,你真的别无选择。
    • 那么使用更昂贵的多处理呢?
    • 多处理只是类固醇上的线程。您可以使用它,但除非您正在运行的代码需要多个内核处理它(提示:您需要对大型数据集和此类或极其图形密集型工作进行一些严肃的科学处理),使用多处理是浪费时间。
    • 我知道这是一个较旧的问题/答案,但我相信目前 celery 应该是公认的答案(正如我在 celery 答案中所述)。在你的代码库中引入多线程可能会带来一大堆问题。 celery 专门用于解决 OP 的问题。
    【解决方案4】:

    嗯,首先 Django 中的信号不是异步的。对于您的特殊情况,我认为post_save 是错误的方法。最直接的方法是简单地触发一个 ajax 请求来查看您喜欢的操作,而不是等待响应。而是在您触发请求后直接修改您的视图/html。

    这当然需要您事先知道您的用户可以喜欢这个项目并且您的请求不会失败。

    【讨论】:

    • 我不太喜欢推测会发生什么,这对我来说是个肮脏的把戏;)克里斯的回答更能说服我。
    • 在我看来,使用线程是一样的。您将生成线程,在前端继续处理,并且不知道线程是失败还是成功。我在 Django 中使用线程有我的公平份额,最后这从来都不是一个好主意(资源方面,从调试的角度来看,等等)。如果不好,您最终会在系统中出现很多僵尸线程。如果您想要异步行为,请使用 celery 之类的任务处理程序。另一种选择是带有 gevent 或类似的更便宜的绿色线程。
    • 确实不错。在我的情况下,如果线程失败,那就没那么糟糕了。我在这里想要的是将需要快速和确认的任务与可能占用更多时间并且静默失败的任务分离。使用线程解决方案,我不必妥协检查是否允许用户喜欢,我还可以向 javascript 发送回确认,而不是假设它有效。那么发送电子邮件和其他通知等其他任务应该没有失败的理由,但我会听从您的建议并检查芹菜之类的。
    猜你喜欢
    • 2012-10-12
    • 1970-01-01
    • 1970-01-01
    • 2017-10-10
    • 2014-05-23
    • 1970-01-01
    • 2016-05-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多