Clojure http-kit请求卡在多个异步调用上

时间:2017-07-28 16:24:37

标签: clojure http-kit

我创建了一个突出问题的小例子:

(->> (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的第一个回调消息。

enter image description here

如果我更改0..3的范围,它将起作用,同步版本也可以。

更新

(info)taoensso.timbre日志记录库

2 个答案:

答案 0 :(得分:2)

我目前的假设是你通过耗尽线程池来陷入僵局:

  1. 您可以根据外部http / get
  2. 创建一个帖子
  3. 如果您创建的请求少于线程池中可用线程的数量,则至少有一个内部http/get可以提供服务(这将需要一个新线程)
    1. 或者,如果您在耗尽线程池之前完成了第一个请求
  4. 一旦线程池中没有线程,内部http/get就不能 得到服务
  5. 由于内部请求无法完成,因此outers永远停留
  6. 您可以检查线程池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 ")))))))

enter image description here