我创建了一个突出问题的小例子:
(->> (range 0 4)
(mapv (fn [i]
(http/get "http://http-kit.org/"
(fn [res]
(info "first callback")
(let [res2 @(http/get "http://http-kit.org/")]
(info "second callback ")))))))
它坚持打印4s的第一个回调消息。
如果我更改0..3的范围,它将起作用,同步版本也可以。
更新
(info)
是taoensso.timbre
日志记录库
答案 0 :(得分:2)
我目前的假设是你通过耗尽线程池来陷入僵局:
http/get
可以提供服务(这将需要一个新线程)
http/get
就不能
得到服务您可以检查线程池http-kit使用偷看http/default-pool
的状态。你可以在那里看到:
#object[java.util.concurrent.ThreadPoolExecutor 0x5a99e5c "java.util.concurrent.ThreadPoolExecutor@5a99e5c[Running, pool size = 8, active threads = 0, queued tasks = 0, completed tasks = 24]"]
当你没有陷入僵局。或者
#object[java.util.concurrent.ThreadPoolExecutor 0x5a99e5c "java.util.concurrent.ThreadPoolExecutor@5a99e5c[Running, pool size = 8, active threads = 8, queued tasks = 8, completed tasks = 28]"]
当你做的时候。
我在我的机器上测试了这个(显示8为(.availableProcessors (Runtime/getRuntime))
),我得到了上面的结果。当我运行超过8个请求时,我陷入了僵局。
此致
答案 1 :(得分:0)
看起来问题是因为http-kit客户端线程池在回调函数完成之前不会释放线程。因此最终会耗尽线程。
所以我开始思考如何更快地制作回调函数并提出这个解决方案:
我为http-kit客户端创建了异步包装函数,在回调中使用clojure.core.async/chan
将结果快速放入通道,然后等待结果并执行大量回调:
(defn async-http-get
[url opts callback]
(let [channel (chan)]
(http/get url opts #(go (>! channel %)))
(go (callback (<! channel)))
nil))
现在使用async-http-get
代替http/get
为我解决问题。
(->> (range 0 4)
(mapv (fn [i]
(async-http-get "http://http-kit.org/"
(fn [res]
(info "first callback")
(let [res2 @(http/get "http://http-kit.org/")]
(info "second callback ")))))))