Val*_*nck 35 clojure nonblocking ring core.async http-kit
我想知道是否可以使用http-kit整合一个完全无阻塞的Clojure后端Web应用程序.
(实际上任何与Ring兼容的http服务器都没关系;我提到了http-kit,因为它声称有一个事件驱动的非阻塞模型).
这个问题是我对非阻塞/异步/事件驱动系统性质的一些误解的症状.如果你和我在同一个地方,这里有一些澄清.
只有当所有(例如,大多数)IO从头开始以非阻塞方式处理时,才能使事件驱动系统具有非阻塞的性能优势(如在Node.js中).这意味着所有数据库驱动程序,HTTP服务器和客户端,Web服务等都必须首先提供异步接口.特别是:
现在,具体来说:
如果我做对了(我不是专家,所以请告诉我,如果我正在做错误的假设),Web应用程序的这种非阻塞模型的原则如下:
从我所看到的,默认情况下,Play Framework(Scala)和Node.js(JavaScript)平台支持此模型,具有基于承诺的实用程序,用于以编程方式管理异步.
让我们尝试使用Compojure路由在基于Ring的clojure应用程序中执行此操作.我有一个通过调用my-handle函数构造响应的路由:
(defroutes my-routes
(GET "/my/url" req (my-handle req))
)
(def my-app (noir.util.middleware/app-handler [my-routes]))
(defn start-my-server! []
(http-kit/run-server my-app))
Run Code Online (Sandbox Code Playgroud)
在Clojure应用程序中管理异步的普遍接受的方式似乎是基于CSP,使用core.async库,我完全没问题.因此,如果我想接受上面列出的非阻塞原则,我将以my-handle这种方式实现:
(require '[clojure.core.async :as a])
(defn my-handle [req]
(a/<!!
(a/go ; `go` makes channels calls asynchronous, so I'm not really waiting here
(let [my-db-resource (a/thread (fetch-my-db-resource)) ; `thread` will delegate the waiting to "weaker" threads
my-web-resource (a/thread (fetch-my-web-resource))]
(construct-my-response (a/<! my-db-resource)
(a/<! my-web-resource)))
)))
Run Code Online (Sandbox Code Playgroud)
CPU密集型construct-my-response任务在go-block中执行,而等待外部资源在thread-blocks中完成,正如Tim Baldridge在core.async(38'55'')上的视频中所建议的那样
但这还不足以使我的应用程序无阻塞.无论什么线程通过我的路线并将调用该my-handle函数,将等待构建响应,对吧?
是否有益(我相信)也可以使这种HTTP处理非阻塞,如果是这样,我怎样才能实现它?
编辑
正如codemomentum指出的那样,对请求进行非阻塞处理的缺失成分是使用http-kit通道.与core.async一起使用,上面的代码会变成这样:
(defn my-handle! [req]
(http-kit/with-channel req channel
(a/go
(let [my-db-resource (a/thread (fetch-my-db-resource))
my-web-resource (a/thread (fetch-my-web-resource))
response (construct-my-response (a/<! my-db-resource)
(a/<! my-web-resource))]
(send! channel response)
(close channel))
)))
Run Code Online (Sandbox Code Playgroud)
这使您可以确实拥抱异步模型.
这个问题是它与Ring中间件几乎不兼容.环中间件使用函数调用来获取响应,这使得它基本上是同步的.更一般地说,事件驱动处理似乎与纯函数编程接口不兼容,因为触发事件意味着具有副作用.
我很高兴知道是否有一个Clojure库来解决这个问题.
小智 6
使用异步方法,您可以在准备好时将数据发送到客户端,而不是在整个准备过程中阻塞线程.
对于http-kit,您应该使用文档中描述的异步处理程序.在以适当的方式将请求委托给异步处理程序之后,您可以实现它,但是您喜欢使用core.async或其他东西.
Async Handler文档位于:http://http-kit.org/server.html#channel