Clojure Ring 是否为每个请求创建一个线程?

Does Clojure Ring create a thread for each request?

我正在制作一个 Messenger 机器人,我正在使用 Ring 作为我的 http 框架。

有时我想在机器人发送的消息之间应用延迟。我的期望是使用 Thread/sleep 是安全的,因为这会使活动线程休眠而不是整个服务器。是这样吗,还是我应该求助于clojure/core.async

这是我在没有 async 的情况下编写的代码:

  (match [reply]

    ; The bot wants to send a message (text, images, videos etc.) after n milliseconds
    [{:message message :delay delay}] 
    (do
      (Thread/sleep interval delay)
      (facebook/send-message sender-id message))
    ; More code would follow...

一个 link 到 Ring 代码,在这个意义上它的行为是明确的,以及任何其他对此事有解释的代码。

假设您正在谈论处理程序中的代码,Thread/sleep 在 Ring 中确实使请求线程休眠。如果您有多个请求,您将耗尽昂贵的服务器线程。

Ring 阻塞的原因是因为(非异步)模型基于函数组合,其中一个函数的结果是另一个函数的输出。所以他们必须等待,我可以在我不知道的代码中准确地指出这一点。

将它放在一个 go-block 中更好,因为那样你就不会阻塞服务器线程。它可以 return 在您发送消息时进行响应。请注意,您不能使用 go 块的结果。

如果您还想要异步响应(不阻塞服务器线程),您可以使用 Pedestal.

对于大多数服务器来说,同步处理程序就足够了,但是如果您正在使用 Thread/sleeps 并且想要响应,我建议您使用异步 Ring 处理程序或 Pedestal 或其他框架。

Ring 是错误的问题:ring 不是 http 服务器,而是对 http 服务器的抽象。 Ring 本身没有固定的线程模型:它真正关心的是你有一个从请求到响应的函数。

真正做出这个决定的是您使用的环形适配器。到目前为止,最常见的是 ring-jetty-adapter,它是一个 jetty http 处理程序,通过 ring 委托给你的函数。码头确实为每个请求提供了一个线程,因此您可以在一个线程中休眠而不会影响其他线程(但正如另一个答案中所述,线程不是免费的,因此您不想定期执行大量操作) .

但是还有其他具有不同线程模型的环处理程序。例如,aleph 包含一个基于 netty 的环形适配器,它在一个小的、有限的线程池中使用 java.nio 进行非阻塞 IO;在那种情况下,睡在 "request thread" 上是非常具有破坏性的。