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

7

我正在制作一个 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...

希望能提供一个链接,其中Ring代码的行为在这方面是清晰的,并且提供任何其他解释。

2个回答

16

针对这个问题,Ring并不是一个http服务器,而是对于http服务器的一种抽象。Ring本身并没有固定的线程模型,它唯一关心的是你是否拥有一个从请求到响应的函数。

真正决定线程模型的是你使用的Ring适配器。迄今为止最常见的是ring-jetty-adapter,它是一个jetty http处理程序,通过ring将请求委托给你的函数。而Jetty确实为每个请求分配了单个线程,因此你可以在一个线程中睡眠而不影响其他线程(但正如另一个答案中所述,线程并非免费,因此你不想经常大量这样做)。

但是也有其他具有不同线程模型的Ring处理程序。例如,aleph包括基于netty的ring适配器,它在一个小的、有限的线程池中使用java.nio进行非阻塞IO;在这种情况下,在“请求线程”上休眠会非常具有破坏性。


好的解释! - Ertuğrul Çetin
1
我想补充一下,使用异步处理程序可以实现延迟而不会占用整个延迟期间的线程,例如通过将响应渲染调度到“ScheduledExecutorService”中。 - Piotrek Bzdyl
确实,这是异步编程的一个巨大优势。但你必须确保真正地去做它,而不是睡眠。 - amalloy

1
假设你在谈论处理程序中的代码,Ring 中的 Thread/sleep 会使请求的线程休眠。如果您有多个请求,则会消耗昂贵的服务器线程。
Ring 阻塞的原因是因为(非异步)模型基于函数组合,其中一个函数的结果是另一个函数的输出。所以它们必须等待,我不知道在代码中确切的位置。
将其放在 go-block 中更好,因为这样您就不会阻塞服务器线程。它可以返回响应,同时您发送消息。请注意,您不能使用来自 go block 的结果。
如果您还想异步地获得响应(而不会阻塞服务器线程),您可以使用 Pedestal 等。
对于大多数服务器来说,同步处理程序已足够,但如果您正在使用 Thread/sleep 并且需要响应,则建议使用异步 Ring 处理程序或 Pedestal 或其他框架。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接